1'use strict'; 2 3/* globals Modernizr app reframe */ 4 5// Our namespace 6window.app = app || {}; 7app.utilities = {}; 8 9app.state = { 10 menuActive: false 11}; 12 13app.elements = { 14 body: document.body, 15 hero: document.querySelector('.hero'), 16 header: document.querySelector('.site-header') 17}; 18 19app.constants = { 20 mediumBreakpoint: 730, 21 headerHeight: 80 // Sorry, magic number here which we need becuase otherwise we would sometimes need to get the height of the header while it is invisible, which is not a thing. 22}; 23 24/* 25 * Browser Unsupported Page 26 * If we are not on the browser unsupported page already, check the site criteria 27 */ 28 29if (window.location.pathname !== '/browser-unsupported/') { 30 // Perform the check based on this siteâs criteria 31 if (Modernizr && !Modernizr.flexbox) { 32 window.location = '/browser-unsupported/'; 33 } 34} 35 36/* 37 * Unified window event tracking method 38 */ 39 40(function () { 41 var _checkPos, checkDimension; 42 43 // Utility function for adding different dimensions to the checkPos loop 44 checkDimension = function checkDimension(key, value, evName) { 45 if (app[key] !== value) { 46 app[key] = value; 47 48 if (evName) { 49 // Dispatch a related event 50 var event = new CustomEvent(evName); 51 52 window.dispatchEvent(event); 53 } 54 } 55 }; 56 57 // Special method for keeping track of window height and window scroll position. These are frequently-used values within our various components. This RAF method ensures they are always up to date. 58 // If you need to do something that relies on winHeight or winScroll, bind to our custom events, not to the windowâs normal scroll or resize events. 59 _checkPos = function checkPos() { 60 checkDimension('winHeight', window.innerHeight, 'cwtHeightChange'); 61 checkDimension('winWidth', window.innerWidth, 'cwtWidthChange'); 62 checkDimension('winScroll', window.scrollY, 'cwtScrollChange'); 63 checkDimension('heroHeight', app.elements.hero.clientHeight, 'cwtHeroHeightChange'); 64 65 window.requestAnimationFrame(_checkPos); 66 }; 67 68 _checkPos(); 69})(); 70 71/* 72 * Menu State Tracking 73 */ 74 75(function () { 76 window.addEventListener('cwtMenuStateChange', function () { 77 document.querySelector('body').setAttribute('data-site-menu-active', app.state.menuActive); 78 }, false); 79})(); 80 81/* 82 * Responsive YouTube Embeds 83 */ 84 85(function () { 86 reframe('iframe:not([src*="https://mercatuscenter.formstack.com"])'); 87 88 reframe('iframe[src*="https://mercatuscenter.formstack.com"]', 'js-reframe-formstack'); 89})(); 90 91/* 92 * Manipulate Newsletter form to get the original styles 93 */ 94 95var styleNewsletterForm = function styleNewsletterForm() { 96 var destination = document.querySelector('.fa-subscribe-form .wpforms-field-email'), 97 border = document.querySelector('.border-below-email-field'), 98 borderCopy = border.cloneNode(true); 99 100 borderCopy.classList.add('visible'); 101 102 if (destination) { 103 destination.appendChild(borderCopy); 104 } 105}; 106 107(function () { 108 styleNewsletterForm(); 109})(); 110'use strict'; 111 112(function () { 113 var animatorInstances = [], 114 Animator; 115 116 // Class Definition 117 Animator = function Animator(element) { 118 var _this = this; 119 120 this.element = element; 121 this.settings = JSON.parse(this.element.dataset.animator); 122 123 this.handleResize(); 124 this.handleScroll(); 125 126 window.addEventListener('cwtHeightChange', function () { 127 _this.handleResize(); 128 _this.handleScroll(); 129 }); 130 131 window.addEventListener('cwtWidthChange', function () { 132 _this.handleResize(); 133 _this.handleScroll(); 134 }); 135 136 window.addEventListener('cwtScrollChange', function () { 137 _this.handleScroll(); 138 }); 139 }; 140 141 Animator.prototype.handleResize = function () { 142 var rangeStart = window.app.winHeight * this.settings.range[0], 143 rangeFinish = window.app.winHeight * this.settings.range[1]; 144 145 this.rangeValue = rangeFinish - rangeStart; 146 }; 147 148 Animator.prototype.handleScroll = function () { 149 var elDiff = window.app.winHeight - this.element.getBoundingClientRect().top, 150 progress = Math.max(Math.min(elDiff / this.rangeValue, 1), 0); // outputs percentage as fraction of 1 151 152 this.updateOpacity(progress); 153 this.updateTransform(progress); 154 }; 155 156 Animator.prototype.updateOpacity = function (progress) { 157 if (this.settings.opacity) { 158 var start = this.settings.opacity[0], 159 finish = this.settings.opacity[1], 160 value = start + (finish - start) * progress; 161 162 this.element.style.opacity = value; 163 } 164 }; 165 166 Animator.prototype.updateTransform = function (progress) { 167 if (this.settings.transform) { 168 var start = parseInt(this.settings.transform[0].translateY, 10), 169 finish = parseInt(this.settings.transform[1].translateY, 10), 170 value = start + (finish - start) * progress; 171 172 this.element.style.transform = 'translateY(' + value + 'px)'; // Note that this will nuke any other transforms on the element. Beware. 173 } 174 }; 175 176 // Instantiation 177 var elements = document.querySelectorAll('[data-animator]'); // eslint-disable-line one-var 178 179 for (var i = 0; i < elements.length; i++) { 180 animatorInstances[i] = new Animator(elements[i]); 181 } 182})(); 183'use strict'; 184 185(function () { 186 var suppressedElements = []; 187 188 document.addEventListener('mousedown', function (ev) { 189 var target = ev.target.closest('a, button, input, select'); 190 191 if (target) { 192 target.style.outline = 'none'; 193 suppressedElements.push(target); 194 } 195 }); 196 197 document.addEventListener('keydown', function () { 198 for (var i = 0; i < suppressedElements.length; i++) { 199 suppressedElements[i].style.outline = null; 200 } 201 }); 202})(); 203'use strict'; 204 205/* globals app TweenLite */ 206 207(function () { 208 var animationDuration = 0.5, 209 body = document.getElementsByTagName('body')[0]; 210 211 // Define some utilities 212 app.utilities.scrolling = { 213 214 // Scroll to a given hash by id 215 scrollToHash: function scrollToHash(hash, success) { 216 var el = document.getElementById(hash.slice(1)); 217 218 if (el) { 219 var gap = Math.max(0, el.offsetTop - document.documentElement.scrollHeight + window.innerHeight); // At the furthest possible scroll position, what is the distance between this elementâs top edge and the viewport top edge? Round negatives down to 0. 220 221 TweenLite.to(window, animationDuration, { 222 scrollTo: { 223 y: hash, // Includes the hash mark 224 offsetY: app.elements.header.clientHeight - gap, // Most of the time we want the offset to be the header height, but sometimes we want to account for the gap in how far the window can actually scroll to expose this element. If there is such a gap, use less offset so that the header still ends up aligned. 225 autoKill: false 226 }, 227 onComplete: success 228 }); 229 } 230 } 231 }; 232 233 // On window load (i.e. all resources have loaded), if there is a hash in the URL, 234 // scroll to it with animation instead of simply allowing the browser "jump" 235 // additionally, if there is a data-scrollto attribute on body, override any hash and scroll there instead 236 if (window.location.hash || body.getAttribute('data-scrollto')) { 237 // Immediately reset the scroll position to counteract any automatic hash-based scrolling the browser is trying to do 238 setTimeout(function () { 239 window.scrollTo(0, 0); 240 }, 1); 241 242 window.addEventListener('load', function () { 243 setTimeout(function () { 244 app.utilities.scrolling.scrollToHash(body.getAttribute('data-scrollto') || window.location.hash); 245 }, 1); // Timeout solves layout delay issue in iOS: https://gist.github.com/mataspetrikas/431639 246 }); 247 } 248 249 // Bind to scroll link triggers on this specific page. 250 document.addEventListener('click', function (ev) { 251 var link = ev.target.closest('a'); 252 253 if (link) { 254 var location = app.utilities.strings.getLocationObject(link.href); 255 256 if (location.hash && location.pathname === window.location.pathname) { 257 app.utilities.scrolling.scrollToHash(location.hash); 258 259 ev.preventDefault(); 260 } 261 } 262 }); 263})(); 264'use strict'; 265 266/* globals app */ 267 268// # String Manipulation functions 269// ------------------------------- 270// Handy for moving keys from language to langage 271// Could even extend the string prototype if you wanted 272 273// _Restrict Scope_ 274(function () { 275 app.utilities.strings = { 276 getLocationObject: function getLocationObject(url) { 277 var a = document.createElement('a'); 278 279 a.href = url; 280 281 return { 282 href: a.href, 283 host: a.host, 284 hostname: a.hostname, 285 port: a.port, 286 pathname: a.pathname, 287 protocol: a.protocol, 288 hash: a.hash, 289 search: a.search 290 }; 291 }, 292 isInternalUrl: function isInternalUrl(url) { 293 var location = app.utilities.strings.getLocationObject(url); 294 295 return window.location.host === location.host; 296 }, 297 getRelativeURL: function getRelativeURL(url) { 298 var location = app.utilities.strings.getLocationObject(url); 299 300 return location.pathname + location.search + location.hash; 301 }, 302 303 304 /* 305 * Capitalize First Letter of String 306 * Ex. this-string => This-string 307 */ 308 309 capitalizeFirstLetter: function capitalizeFirstLetter(string) { 310 return string.charAt(0).toUpperCase() + string.slice(1); 311 }, 312 313 314 /* 315 * Convert dashed string to camel case string 316 * Ex. this-string => thisString 317 */ 318 319 dashesToCamelCase: function dashesToCamelCase(string) { 320 return string.replace(/-([a-z])/g, function (g) { 321 return g[1].toUpperCase(); 322 }); 323 }, 324 325 326 /*
327 * Convert dashed string to a capitalized method name for our JS 328 * Ex. this-string => ThisString 329 */ 330 331 dashesToMethodName: function dashesToMethodName(string) { 332 return app.utilities.strings.capitalizeFirstLetter(app.utilities.strings.dashesToCamelCase(string)); 333 }, 334 335 336 /* 337 * Convert underscored string to camel case 338 * Ex. this_string => thisString 339 */ 340 341 underscoreToCamelCase: function underscoreToCamelCase(string) { 342 return string.replace(/_([a-z])/g, function (g) { 343 return g[1].toUpperCase(); 344 }); 345 }, 346 347 348 /* 349 * Convert dashed string to a capitalized method name for our JS 350 * Ex. this_string => ThisString 351 */ 352 353 underscoreToMethodName: function underscoreToMethodName(string) { 354 return app.utilities.strings.capitalizeFirstLetter(app.utilities.strings.underscoreToCamelCase(string)); 355 } 356 }; 357})(); 358'use strict'; 359 360/* global dataLayer */ 361 362(function () { 363 var domain = document.domain.split('.').reverse()[1] + '.' + document.domain.split('.').reverse()[0]; 364 365 function success(url, target) { 366 if (target) { 367 window.open(url, target); 368 } else { 369 window.location.href = url; 370 } 371 } 372 373 function handleOutboundLink(url, id, target) { 374 var successful = void 0; 375 376 // Log event to Analytics, once done, go to the link 377 378 dataLayer.push({ 379 event: 'User Event', 380 action: id, 381 category: 'outbound-link-click', 382 label: url, 383 eventCallback: function eventCallback() { 384 success(url, target); 385 successful = true; 386 } 387 }); 388 389 // Set backup timeout in case it doesnât work 390 setTimeout(function () { 391 !successful && success(url, target); 392 }, 500); 393 } 394 395 // Add event listener 396 document.addEventListener('click', function (ev) { 397 var link = ev.target.closest('a'); 398 399 if (link) { 400 var url = link.getAttribute('href'), 401 id = link.getAttribute('data-click-id'), 402 target = link.getAttribute('target'), 403 myDomain = url.match(domain); // Query the href for the top level domain (xxxxx.com) 404 405 // If link is outbound 406 if (url.indexOf('http') === 0 && // Relative links can't be outbound 407 url.match(/^(https?:|\/\/)/i) && !myDomain // Only absolute links that aren't our domain 408 || url.match(/^mailto/i)) { 409 ev.preventDefault(); 410 handleOutboundLink(url, id, target); 411 } 412 } 413 }); 414})(); 415'use strict'; 416 417/* global dataLayer */ 418 419// Form handling 420// Includes event tracking and bare-bones form validation 421// Only accounts for presence/absence of required fields. 422// Further validation occurs at the browser level, and in Pardot if all else fails. 423 424(function () { 425 var forms = document.getElementsByTagName('form:not("fsForm")'), 426 i; 427 428 var _loop = function _loop() { 429 var form = forms[i]; 430 431 validate(form); 432 sendSuccessOrFailureEvent(form); 433 434 form.addEventListener('keyup', function () { 435 validate(form); 436 }); 437 438 form.addEventListener('submit', function (ev) { 439 handleSubmission(ev, form); 440 }); 441 }; 442 443 for (i = 0; i < forms.length; i++) { 444 _loop(); 445 } 446 447 // Callback to run on form submit 448 function handleSubmission(ev, form) { 449 ev.preventDefault(); 450 451 fixURL(); 452 453 dataLayer.push({ 454 event: 'User Event', 455 action: 'submission', 456 category: 'forms', 457 label: form.id, 458 eventCallback: function eventCallback() { 459 form.submit(); 460 } 461 }); 462 463 // Set a timeout to submit just in case the above fails 464 setTimeout(function () { 465 form.submit(); 466 }, 500); 467 } 468 469 // Pardot doesn't clear the form errors out of the URL properly on submit, so we do that here 470 function fixURL() { 471 var url = [location.protocol, '//', location.host, location.pathname].join(''); 472 473 window.history.replaceState({}, '', url); 474 } 475 476 function sendSuccessOrFailureEvent(form) { 477 // If there is a form alert, that means we should issue a success or failure event. Track which one it is and send the appropriate response 478 if (form.dataset.alert) { 479 dataLayer.push({ 480 event: 'User Event', 481 action: form.dataset.alert === 'success' ? 'success' : 'failure', 482 category: 'forms', 483 label: form.id 484 }); 485 } 486 } 487 488 // Validation Utilities 489 function validate(form) { 490 var button = form.getElementsByTagName('button')[0], 491 isValid = isFormValid(form); 492 493 form.dataset.isValid = isValid; 494 button.disabled = !isValid; 495 } 496 497 function isFormValid(form) {
498 var valid = true, 499 inputs = form.getElementsByTagName('input'), 500 i; 501 502 for (i = 0; i < inputs.length; i++) { 503 if (inputs[i].required && !inputs[i].value) { 504 // If the input has a validitystate (meaning it is reqiured) 505 valid = false; 506 } 507 } 508 509 return valid; 510 } 511})(); 512'use strict'; 513 514/* global dataLayer */ 515 516(function () { 517 var currentlyPlaying = undefined; 518 519 document.addEventListener('click', function (ev) { 520 var clickedButton = ev.target.closest('.card__audio-button'), 521 clickedCard = ev.target.closest('.card'); 522 523 if (clickedButton) { 524 if (!clickedCard.getAttribute('state-audio-playing')) { 525 currentlyPlaying && pauseCard(currentlyPlaying); 526 playCard(clickedCard); 527 528 currentlyPlaying = clickedCard; 529 } else { 530 pauseCard(clickedCard); 531 532 currentlyPlaying = undefined; 533 } 534 } else if (clickedCard) { 535 var ctas = clickedCard.getElementsByClassName('card__cta'), 536 target = undefined; 537 538 for (var i = 0; i < ctas.length; i++) { 539 var displayValue = window.getComputedStyle(ctas[i].closest('span')).getPropertyValue('display'); 540 541 if (displayValue !== 'none') { 542 target = ctas[i].href; 543 } 544 } 545 546 window.location = target; 547 } 548 }); 549 550 function playCard(card) { 551 if (!card.audio) { 552 card.audio = new Audio(card.dataset.audio); 553 } 554 555 card.audio.play(); 556 card.setAttribute('state-audio-playing', true); 557 558 dataLayer.push({ 559 event: 'User Event', 560 action: 'play', 561 category: 'card-audio', 562 label: card.getElementsByTagName('h3')[0].textContent 563 }); 564 } 565 566 function pauseCard(card) { 567 card.audio.pause(); 568 card.removeAttribute('state-audio-playing'); 569 570 dataLayer.push({ 571 event: 'User Event', 572 action: 'pause', 573 category: 'card-audio', 574 label: card.getElementsByTagName('h3')[0].textContent 575 }); 576 } 577})(); 578'use strict'; 579 580/* globals app */ 581 582(function () { 583 var el = document.getElementsByClassName('site-menu-trigger')[0]; 584 585 el.addEventListener('click', function () { 586 app.state.menuActive = !app.state.menuActive; 587 588 // Create a new event 589 var event = new CustomEvent('cwtMenuStateChange'); 590 591 // Dispatch the event 592 window.dispatchEvent(event); 593 }); 594 595 // We also want to be able to close the menu conditionally for some things 596 var closeButtons = document.querySelectorAll('[data-close-menu="1"]'); 597 598 // If we have any close buttons 599 if (closeButtons.length) { 600 601 // iterate over the and add close functionality. 602 Array.from(closeButtons).map(function (v) { 603 v.addEventListener('click', function () { 604 app.state.menuActive = false; 605 606 // Create a new event 607 var event = new CustomEvent('cwtMenuStateChange'); 608 609 // Dispatch the event 610 window.dispatchEvent(event); 611 }); 612 }); 613 } 614})(); 615// (function() { 616// var textBlockLinks = document.querySelectorAll('.text-block a[href^="mailto:"]'); 617// 618// textBlockLinks.forEach((link) => { 619// var newLinkContent = ` 620// <main>${link.text}</main> 621// <div class="secondary-cta__border" style="background-color: #9b26b6" role="presentation"></div>`; 622// 623// link.classList.add('secondary-cta'); 624// link.innerHTML = newLinkContent; 625// }); 626// 627// })(); 628"use strict"; 629'use strict'; 630 631/* globals TimelineLite app Power1 dataLayer */ 632 633(function () { 634 var animationDuration = 0.3; 635 636 var el = document.querySelectorAll('.easter-egg'), 637 index = 0, 638 // Current easter egg index 639 closeButton, 640 backgroundSource, 641 backgroundImage, 642 video, 643 triggers, 644 progressLabel, 645 progressBar, 646 timeline = new TimelineLite(); 647 648 /* 649 * Define functions 650 */ 651 652 // Checker which looks at all the triggers to see which should be active 653 function updateTriggers() { 654 for (var i = 0; i < triggers.length; i++) { 655 triggers[i].dataset.available = i === index ? 'true' : 'false'; 656 triggers[i].dataset.completed = i < index ? 'true' : 'false'; 657 } 658 } 659 660 function showProgress() { 661 var currentIndex = index,
662 // Stash this so that we can use the current index inside the callback, not the future index. 663 progressPct = index / triggers.length; 664 665 // Kill any active animations 666 timeline.progress(1).kill(); 667 668 // Bind the scroll cancelation event 669 bindCancelation(); 670 671 // Set the right copy 672 progressLabel.innerHTML = triggers[index - 1].dataset.label; // The 0th label is for the 1th index, so subtract one 673 674 // Set a body attribute so that all views can react to the fact that the easter egg is showing 675 app.elements.body.dataset.showingEasterEggProgress = 'true'; 676 677 // Run the animations 678 timeline.fromTo(progressBar, animationDuration * 6, { 679 opacity: 0, 680 width: (progressPct - 1 / triggers.length) * 100 + '%' // Prior trigger percentage width 681 }, { 682 opacity: 1, 683 ease: Power1.easeOut, 684 width: progressPct * 100 + '%' 685 }).fromTo(progressLabel, animationDuration, { 686 opacity: 0 687 }, { 688 opacity: 1, 689 onComplete: function onComplete() { 690 // Load the background image if we are at the n-1th trigger 691 if (currentIndex === triggers.length - 1) { 692 loadBackground(); 693 } 694 695 // Run the success message if we are at the end 696 if (currentIndex === triggers.length) { 697 showReward(); 698 } 699 } 700 }, '-=' + animationDuration * 4).to('.hero__easter-egg-progress', animationDuration, { 701 opacity: 0, 702 clearProps: 'all', 703 onComplete: function onComplete() { 704 // Remove the special body attribute 705 delete app.elements.body.dataset.showingEasterEggProgress; 706 707 // Unbind the backup scroll bind 708 unbindCancelation(); 709 } 710 }, '+=' + animationDuration * 4); 711 } 712 713 // When the user scrolls while we are showing the progress bar, we want to check to see if we need to cancel the progress message. 714 function bindCancelation() { 715 document.addEventListener('scroll', cancelMessage); 716 } 717 718 function unbindCancelation() { 719 document.removeEventListener('scroll', cancelMessage); 720 } 721 722 function cancelMessage() { 723 if (!app.elements.hero.getAttribute('data-is-fixed')) { 724 timeline.progress(1).kill(); 725 } 726 } 727 728 function loadBackground() { 729 for (var i = 0; i < backgroundSource.length; i++) { 730 backgroundSource[i].srcset = backgroundSource[i].dataset.srcset; 731 732 delete backgroundSource[i].dataset.srcset; 733 } 734 735 backgroundImage.src = backgroundImage.dataset.src; 736 737 delete backgroundImage.dataset.src; 738 } 739 740 function showReward() { 741 app.elements.body.dataset.showingEasterEgg = true; 742 743 timeline.fromTo('.easter-egg', animationDuration * 2, { 744 opacity: 0, 745 y: -32 746 }, { 747 opacity: 1, 748 y: 0 749 }).fromTo(video, animationDuration * 4, { 750 opacity: 0 751 }, { 752 opacity: 1, 753 onComplete: function onComplete() { 754 video.play(); 755 } 756 }, '-=' + animationDuration * 2).fromTo('.easter-egg article', animationDuration * 4, { 757 opacity: 0 758 }, { 759 opacity: 1 760 }, '-=' + animationDuration * 2).fromTo('.easter-egg__tray', animationDuration * 4, { 761 opacity: 0 762 }, { 763 opacity: 1 764 }, '-=' + animationDuration * 2); 765 } 766 767 function hideReward() { 768 timeline.progress(1).kill().to('.easter-egg', animationDuration * 2, { 769 opacity: 0, 770 y: -32, 771 onComplete: function onComplete() { 772 video.pause(); 773 774 delete app.elements.body.dataset.showingEasterEgg; 775 } 776 }); 777 } 778 779 /* 780 * If the element exists, run all the stuff 781 */ 782 783 if (el.length) { 784 closeButton = document.querySelectorAll('.easter-egg__close')[0]; 785 backgroundSource = document.querySelectorAll('.easter-egg__bg source')[0]; 786 backgroundImage = document.querySelectorAll('.easter-egg__bg img')[0]; 787 video = document.querySelectorAll('.easter-egg video')[0]; 788 triggers = document.getElementsByClassName('easter-egg-trigger'); 789 progressLabel = document.querySelectorAll('.hero__easter-egg-progress label')[0]; 790 progressBar = document.querySelectorAll('.hero__easter-egg-progress data')[0]; 791 792 // Run an initial check 793 updateTriggers(); 794 795 // Event listener for clicks on the triggers 796 document.addEventListener('click', function (ev) { 797 var trigger = ev.target.closest('.easter-egg-trigger'); 798 799 if (trigger) { 800 if (trigger.dataset.available === 'true') { 801 // Remember that these are always strings 802 index++; 803 804 updateTriggers(); 805 806 // If the hero is not docked, scroll down to make that happen 807 if (!app.elements.hero.getAttribute('data-is-fixed')) { 808 app.utilities.scrolling.scrollToHash('#main', showProgress); 809 } else { 810 showProgress(); 811 } 812 813 dataLayer.push({ 814 event: 'User Event', 815 action: 'trigger-click', 816 category: 'easter-egg', 817 label: trigger.textContent 818 }); 819 } 820 } 821 }); 822 823 closeButton.addEventListener('click', hideReward, true); 824 825 window.addEventListener('keyup', function (ev) { 826 if (ev.keyCode === 27 && app.elements.body.dataset.showingEasterEgg) { 827 hideReward(); 828 } 829 }); 830 } 831})(); 832'use strict'; 833 834/* globals TweenLite app */ 835 836(function () { 837 var dampener = 0.5, 838 bgs = document.getElementsByClassName('geo__bg'), 839 squares = document.getElementsByClassName('geo__bg--squares'), 840 triangles = document.getElementsByClassName('geo__bg--triangles'), 841 circles = document.getElementsByClassName('geo__bg--circles'); 842 843 var lastScrollDepth, 844 bodyHeight = app.elements.body.clientHeight; 845 846 function checkLocation() { 847 if (window.innerWidth > app.constants.mediumBreakpoint) { 848 var scrollDepthRaw = (app.winScroll + app.winHeight / 2) / bodyHeight - 0.5, 849 scrollDepth = Math.floor(scrollDepthRaw * dampener * 1000) / 1000; // Restrict to 3 significant digits 850 851 if (scrollDepth !== lastScrollDepth) { 852 lastScrollDepth = scrollDepth; 853 854 setLocation(); 855 } 856 } 857 } 858 859 function setLocation() { 860 var scale = 1 + lastScrollDepth; 861 862 TweenLite.set(squares, { 863 rotation: lastScrollDepth * 100, 864 scale: scale 865 }); 866 867 TweenLite.set(triangles, { 868 rotation: lastScrollDepth * -100, 869 scale: scale 870 }); 871 872 TweenLite.set(circles, { 873 scale: scale 874 }); 875 } 876 877 // Run and Bind 878 checkLocation(); 879 880 window.addEventListener('cwtHeightChange', checkLocation); 881 window.addEventListener('cwtScrollChange', checkLocation); 882 883 // Perform a cross-browser set for transform origin and shape centering. This creates the right position but is resistant to window resize, unlike if we do this in CSS. 884 TweenLite.set(bgs, { 885 x: '-50%', 886 y: '-50%', 887 transformOrigin: '50% 50%' 888 }); 889})(); 890'use strict'; 891 892/* globals app */ 893 894(function () { 895 // Pull any potentially-needed elements into vars, so we never have to fetch them during a rAF 896 var shade = app.elements.hero.getElementsByClassName('hero__shade')[0]; 897 898 var isFixed; 899 900 // Position setter function which writes to DOM and creates tweens when checker decides itâs time 901 // Be careful not to have any DOM queries or checks in here. This has to run in 16ms. It is just a setter. 902 function setPos() { 903 if (app.winScroll >= app.heroHeight - app.constants.headerHeight) { 904 // If the user has scrolled far enough that the visible pixel height of the hero is equal to the header height, make the hero stick in place using a transform, so that it can act as a background for the header. 905 // If the hero has not already been marked as fixed... 906 !isFixed && setFixed(); 907 } else { 908 // If the hero should be in its normal position and the hero was previously fixed 909 isFixed && setStatic(); 910 911 // Whether or not the header was previously fixed, set the shade to the right height given the current hero position on screen 912 shade.style.height = Math.max(app.heroHeight - app.winScroll, app.c
912onstants.headerHeight) + 'px'; 913 } 914 } 915 916 // Utility to set the hero as 'fixed' when appropriate 917 function setFixed() { 918 isFixed = true; 919 app.elements.hero.setAttribute('data-is-fixed', 'true'); 920 921 shade.style.height = app.constants.headerHeight; 922 } 923 924 // Utility function to set the hero as static when appropriate. 925 function setStatic() { 926 isFixed = false; 927 app.elements.hero.removeAttribute('data-is-fixed'); 928 } 929 930 if (app.elements.hero.getAttribute('data-fixed') !== 'true') { 931 // Kick off the main positioning loop, tying into the global scroll handler 932 setPos(); 933 window.addEventListener('cwtScrollChange', setPos); 934 window.addEventListener('cwtWidthChange', setPos); 935 window.addEventListener('cwtHeroHeightChange', setPos); 936 937 // Set a flag after the first time this runs so we know any subsequent runs are changes 938 app.elements.hero.dataset.isLoaded = true; 939 } 940})(); 941'use strict'; 942 943/* global app */ 944 945(function () { 946 var heroBg = document.getElementsByClassName('hero__bg')[0], 947 body = document.querySelector('body'); 948 949 // Hero height management 950 // Continually match the BG image height to the main areaâs height. Canât be done in CSS becuase the BG is not inside the normal hero container. 951 function setHeroHeight() { 952 heroBg.style.height = app.heroHeight + 'px'; 953 } 954 955 if (['episode', 'archive-episode'].indexOf(body.getAttribute('data-template')) === -1) { 956 setHeroHeight(); 957 window.addEventListener('cwtHeroHeightChange', setHeroHeight); 958 } 959})(); 960'use strict'; 961 962/* globals app TimelineLite Modernizr */ 963 964(function () { 965 var isVideoFaded, 966 timeline = new TimelineLite(), 967 logoVideo = document.getElementsByClassName('hero__logo--video')[0], 968 logoImage = document.getElementsByClassName('hero__logo--image')[0], 969 animationDuration = 2; 970 971 // If the conditions are met, run the animtion 972 if (document.getElementsByTagName('body')[0].dataset.template === 'home' && app.isFirstLoad) { 973 handleAnimation(); 974 975 if (Modernizr.backgroundblendmode && window.innerWidth >= app.constants.mediumBreakpoint) { 976 handleLogo(); 977 } else { 978 logoImage.setAttribute('data-showing', true); 979 logoVideo.remove(); 980 } 981 } 982 983 function handleAnimation() { 984 var timeline = new TimelineLite(); 985 986 // Run primary animation 987 timeline.to('.hero__image', 1, { 988 opacity: 1 989 }, 0.25).to('.hero__title', 1, { 990 opacity: 1 991 }, 0.5).to('.hero__blurb', 1, { 992 opacity: 1 993 }, 1).to('.hero .primary-cta', 1, { 994 opacity: 1 995 }, 1).fromTo('.hero__alert', 1, { 996 opacity: 0, 997 y: '-40px' 998 }, { 999 opacity: 1, 1000 y: 0 1001 }, 1.75).fromTo('.hero__tray', 1, { 1002 opacity: 0, 1003 y: '40px' 1004 }, { 1005 opacity: 1, 1006 y: 0 1007 }, 1.75); 1008 } 1009 1010 // Very Magic-numbery logic to seamlessly transition between the moving video file and the logo SVG 1011 function handleLogo() { 1012 // Add the video logo source based on the screen size 1013 if (window.innerWidth >= window.app.constants.mediumBreakpoint && window.devicePixelRatio > 1) { 1014 logoVideo.innerHTML = '<source src="https://cwtstg.wpengine.com/wp-content/uploads/required/logo--retina.mp4" height="210" width="420" type="video/mp4">'; 1015 } else if (window.innerWidth < window.app.constants.mediumBreakpoint && window.devicePixelRatio <= 1) { 1016 logoVideo.innerHTML = '<source src="https://cwtstg.wpengine.com/wp-content/uploads/required/logo--small.mp4" height="53" width="106" type="video/mp4">'; 1017 } else { 1018 logoVideo.innerHTML = '<source src="https://cwtstg.wpengine.com/wp-content/uploads/required/logo.mp4" height="105" width="210" type="video/mp4">'; 1019 } 1020 1021 // When the video has run, fade it out and fade in the solid logo (which looks nicer on most screens) 1022 logoVideo.addEventListener('ended', removeVideo); 1023 1024 // Or, if the user scrolls past the logo, remove the video right away 1025 window.addEventListener('cwtScrollChange', function () { 1026 removeVideo(false); 1027 }); 1028 } 1029 1030 function removeVideo() { 1031 var animate = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : true; 1032 1033 if (!isVideoFaded) { 1034 // Once the video has ended, animate it out and animate the static logo in. 1035 logoImage.setAttribute('data-showing', true); 1036 1037 timeline.fromTo(logoImage, animate ? animationDuration : 0, { 1038 opacity: 0 1039 }, { 1040 opacity: 1 1041 }); 1042 1043 timeline.to(logoVideo, animate ? animationDuration : 0, { 1044 opacity: 0, 1045 onComplete: function onComplete() { 1046 logoVideo.remove(); 1047 } 1048 }, '-=0.1'); 1049 } 1050 1051 isVideoFaded = true; 1052 } 1053})(); 1054'use strict'; 1055 1056/* globals app */ 1057 1058(function () { 1059 var el = document.getElementsByClassName('site-header')[0], 1060 topOffset = el.offsetTop; // Usually will be 0, but if there is a site alert, it will be non-zero. 1061 1062 // Create an instance variable that tracks the last Y position so that we can continually check against it 1063 var isFaded, elBelowTop, elBelowBottom; 1064 1065 function setPos() { 1066 var belowTop = app.winScroll > topOffset, 1067 belowBottom = app.winScroll >= app.heroHeight - app.constants.headerHeight; 1068 1069 // Set some state attributes so that CSS can react to the various situations 1070 if (elBelowTop !== belowTop) { 1071 el.setAttribute('data-below-top', belowTop); 1072 elBelowTop = belowTop; // Remember this to trigger future DOM attribute reads/writes only when necessary 1073 } 1074 1075 if (elBelowBottom !== belowBottom) { 1076 el.setAttribute('data-below-bottom', belowBottom); 1077 elBelowBottom = belowBottom; // Remember this to trigger future DOM attribute reads/writes only when necessary 1078 } 1079 1080 if (belowTop && !belowBottom && !isFaded) { 1081 // We are within the area in which the main element should disappear 1082 el.setAttribute('data-is-faded', true); 1083 isFaded = true; 1084 } else if ((!belowTop || belowBottom) && isFaded) { 1085 el.setAttribute('data-is-faded', false); 1086 isFaded = false;
1087 } 1088 } 1089 1090 setPos(); 1091 window.addEventListener('cwtScrollChange', setPos); 1092 window.addEventListener('cwtWidthChange', setPos); 1093 window.addEventListener('cwtHeroHeightChange', setPos); 1094})(); 1095'use strict'; 1096 1097/* globals */ 1098 1099(function () { 1100 var el = document.getElementsByClassName('tab-nav')[0]; 1101 var state = false, 1102 pos; 1103 1104 if (document.getElementsByClassName('tab-nav').length) { 1105 pos = offset(el, 200); 1106 checkPos(); 1107 window.addEventListener('cwtScrollChange', checkPos); 1108 window.addEventListener('resize', function () { 1109 this.clearTimeout(t); 1110 var t = setTimeout(function () { 1111 el.setAttribute('data-fixed', false); 1112 state = false; 1113 pos = offset(el, 200); 1114 checkPos(); 1115 }, 200); 1116 }); 1117 } 1118 1119 function offset(el, extra) { 1120 var rect = el.getBoundingClientRect(), 1121 scrollTop = window.pageYOffset || document.documentElement.scrollTop; 1122 1123 extra = extra || 60; 1124 1125 return rect.top + scrollTop - extra; 1126 } 1127 1128 function checkPos() { 1129 if (window.scrollY > pos && state === false) { 1130 state = true; 1131 el.setAttribute('data-fixed', true); 1132 } else if (window.scrollY <= pos && state === true) { 1133 state = false; 1134 el.setAttribute('data-fixed', false); 1135 } 1136 } 1137})();
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.