1//navigation near edge detection 2document.addEventListener('DOMContentLoaded', function () { 3 const navItems = document.querySelectorAll('.navigation__item.has-drop-down'); 4 5 function calculateEdgePositions() { 6 navItems.forEach(item => { 7 const rect = item.getBoundingClientRect(); 8 const viewportWidth = window.innerWidth; 9 const spaceOnRight = viewportWidth - rect.right; 10 11 if (spaceOnRight < 300) { 12 item.classList.add('near-edge'); 13 } else { 14 item.classList.remove('near-edge'); 15 } 16 }); 17 } 18 19 calculateEdgePositions(); 20 21 let resizeTimeout; 22 window.addEventListener('resize', function () { 23 clearTimeout(resizeTimeout); 24 resizeTimeout = setTimeout(calculateEdgePositions, 100); 25 }); 26}); 27 28// page init; 29(function () { 30 'use strict'; 31 var requestAnimationFrame = 32 window.requestAnimationFrame || 33 window.mozRequestAnimationFrame || 34 window.webkitRequestAnimationFrame || 35 window.msRequestAnimationFrame || 36 function (f) { 37 return setTimeout(f, 17); 38 }; 39 40 var cancelAnimationFrame = 41 window.cancelAnimationFrame || 42 window.mozCancelAnimationFrame || 43 function (requestId) { 44 clearTimeout(requestId); 45 }; 46 /** 47 * Property Decorator constant 48 * @param value 49 * @returns {{enumerable: boolean, value: *}} 50 */ 51 52 function constant(value) { 53 return { 54 enumerable: true, 55 value: value, 56 }; 57 } 58 59 function mutable(value) { 60 return { 61 enumerable: true, 62 writable: true, 63 value: value, 64 }; 65 } 66 67 /** 68 * Property Decorator Get/Set 69 * @param getter 70 * @param setter 71 * @returns {{enumerable: boolean, get: *, set: *}} 72 */ 73 function getterSetter(getter, setter) { 74 return { 75 enumerable: true, 76 get: getter, 77 set: setter, 78 }; 79 } 80 81 function abstractMethod() { 82 throw new Error('This method has not been configured!'); 83 } 84 85 /** 86 * @param $ {JQueryStatic} 87 */ 88 jQuery(document).ready(function ($) { 89 var $body = $('body'), 90 $window = $(window), 91 $noPlace = $('<span></span>'), 92 noPlace = $noPlace.get(0); 93 var $contactForm = $('.contactform').first(); 94 95 function throttleResize(callback) { 96 var id = 0; 97 98 function throttle() { 99 cancelAnimationFrame(id); 100 id = requestAnimationFrame(callback); 101 } 102 return { 103 start: function () { 104 $window.on('resize', throttle); 105 }, 106 stop: function () { 107 $window.off('resize', throttle); 108 cancelAnimationFrame(id); 109 id = 0; 110 }, 111 }; 112 } 113 114 function scrollTo($el) { 115 return function () { 116 $('html, body').animate( 117 { 118 scrollTop: $el.offset().top, 119 }, 120 'slow' 121 ); 122 }; 123 } 124 125 function getPLESection($target) { 126 return $target.closest('.section[data-control="section"]'); 127 } 128 129 /** 130 * @param {HTMLElement} child 131 * @param {Element} container 132 * @returns {Number} 133 */ 134 function absoluteOffsetFrom(child, container) { 135 var total = 0; 136 for ( 137 var currentChild = child; 138 currentChild && 139 currentChild !== container && 140 container.contains(currentChild); 141 currentChild = currentChild.offsetParent 142 ) { 143 total += currentChild.offsetTop; 144 } 145 return total; 146 } 147 148 function positionOnSection($menuBlock) { 149 var menuBlock = $menuBlock.get(0), 150 $sectionBlock = getPLESection($menuBlock), 151 sectionBlock = $sectionBlock.get(0) || noPlace; 152 return function () { 153 var relativeParent = menuBlock.offsetParent; 154 $menuBlock.css({ 155 width: $body.width() + 'px', 156 left: -relativeParent.getBoundingClientRect().left, 157 top: 158 $sectionBlock.outerHeight() - 159 absoluteOffsetFrom(relativeParent, sectionBlock), 160 }); 161 }; 162 } 163 164 /** 165 * use common script for group menu option 166 * replace the global scope nav menu variables 167 * prepare the menu and add the more button 168 */ 169 function groupNavMoreButton($el) { 170 //menuHolder = $el; 171 //menu = $el.find('.more_nav'); 172 //currentMenu = menu; 173 //currentMenuWidth = menuHolder.outerWidth(true); 174 //menuChildrenCount = currentMenu.children().length; 175 //origMenuContent = ''; 176 //moreButton = $('<li class="navigation__item navigation__item--default has-drop-down more"> <a href="#" class="navigation__item--link">More</a> <ul class="navigation__list navigation__list--sub"></ul> </li>'); 177 //allMenus = []; 178 //menuPrepare(); 179 //addMoreButton(); 180 } 181 182 (function NavigationLayoutA() { 183 var expandedClass = 'navigation-open', 184 megaMenuClass = 'mega-menu', 185 expandedSelector = '.' + expandedClass; 186 $('.component.navigation .navigation-a').each(function (index, navEl) { 187 new DesktopMenu(navEl); 188 }); 189 190 /** 191 * @param element {Element} 192 * @constructor 193 */ 194 function DesktopMenu(element) { 195 var dis = this; 196 var watchingBody = false;
197 this.el = element; 198 /** 199 * @type {jQuery} 200 */ 201 this.$el = $(element); 202 // call groupNavMoreButton() before manipulation 203 this.$el.data('more-button') === 1 ? groupNavMoreButton(this.$el) : ''; 204 this.$ul = this.$el.children('ul:first-child'); 205 var $navItems = this.$el.children('ul').children('li'); 206 var focusTree = { 207 prev: function ($a) { 208 $a.parent('li').prev('li').children('a').focus(); 209 }, 210 next: function ($a) { 211 $a.parent('li').next('li').children('a').focus(); 212 }, 213 parent: function ($a) { 214 $a.parent('li').parent('ul').siblings('a').focus(); 215 }, 216 child: function ($a) { 217 $a.siblings('ul').find('> li:first-child > a:first-child').focus(); 218 }, 219 }; 220 221 function isTopRow(el) { 222 return dis.$ul.children('li').children('a').is(el); 223 } 224 var keyboardNav = { 225 ArrowDown: function (event, $a) { 226 if (isTopRow(event.target)) { 227 focusTree.child($a); 228 } else { 229 focusTree.next($a); 230 } 231 }, 232 ArrowUp: function (event, $a) { 233 if (!isTopRow(event.target)) { 234 focusTree.prev($a); 235 } 236 }, 237 ArrowLeft: function (event, $a) { 238 if (isTopRow(event.target)) { 239 focusTree.prev($a); 240 } else { 241 focusTree.parent($a); 242 } 243 }, 244 ArrowRight: function (event, $a) { 245 if (isTopRow(event.target)) { 246 focusTree.next($a); 247 } else { 248 focusTree.child($a); 249 } 250 }, 251 }; 252 253 this.$el.on( 254 'keydown', 255 '.navigation__item--link:focus', 256 function kbEventRouter(event) { 257 keyboardNav.hasOwnProperty(event.key) && 258 keyboardNav[event.key](event, $(event.target)); 259 } 260 ); 261 262 this.subMenuR = $navItems.toArray().map(function (li) { 263 return new ( 264 li.classList.contains(megaMenuClass) 265 ? DesktopSubMenuItemDefault 266 : DesktopSubMenuItemDefault 267 )(li, dis); 268 }); 269 270 function offClick(evt) { 271 if (!dis.el.contains(evt.target)) { 272 dis.closeAll(); 273 } 274 } 275 276 this.watchAfterOpen = function () { 277 if (!watchingBody) { 278 watchingBody = true; 279 $body.on('click touchstart', offClick); 280 } 281 }; 282 283 this.ignoreAfterClose = function () { 284 if (watchingBody) { 285 watchingBody = false; 286 $body.off('click touchstart', offClick); 287 } 288 }; 289 } 290 291 Object.defineProperties(DesktopMenu, {}); 292 Object.defineProperties(DesktopMenu.prototype, { 293 hasFocus: getterSetter(function () { 294 return Boolean(this.$el.find('a:focus').length); 295 }), 296 expandedClass: constant(expandedClass), 297 expandedSelector: constant(expandedSelector), 298 markOpened: constant(function () { 299 this.watchAfterOpen(); 300 }), 301 closeAll: constant(function () { 302 this.$el.find(this.expandedSelector).removeClass(this.expandedClass); 303 this.ignoreAfterClose(); 304 }), 305 watchAfterOpen: mutable(abstractMethod), 306 ignoreAfterClose: mutable(abstractMethod), 307 }); 308 309 /** 310 * @param element {HTMLLIElement} 311 * @param root {DesktopMenu} 312 * @param parent {=DesktopSubMenuItem} 313 * @constructor 314 */ 315 function DesktopSubMenuItemDefault(element, root, parent) { 316 var dis = this; 317 this.root = root; 318 this.parent = parent || null; 319 this.el = element; 320 this.$el = $(element); 321 this.$a = this.$el.children('a'); 322 this.$ul = this.$el.children('ul'); 323 324 this.$a.on('focus', function () { 325 dis.clearExpand(); 326 dis.expand(); 327 }); 328 this.$ul 329 .find('a') 330 .last() 331 .on('blur', function () { 332 dis.contract(); 333 }); 334 335 if (this.$ul.length) { 336 this.$el.hover( 337 function over() { 338 dis.expand(); 339 }, 340 function out(evt) { 341 dis.contract(); 342 } 343 ); 344 this.$a.on('touchend', function (evt) { 345 if (!dis.isExpanded) { 346 dis.clearExpand(); 347 dis.expand(); 348 return false; 349 } 350 }); 351 352 this.subMenuR = this.$ul 353 .children('li') 354 .toArray() 355 .map(function (li) { 356 return new DesktopSubMenuItemDefault(li, root, dis); 357 }); 358 } else { 359 this.subMenuR = []; 360 } 361 } 362 Object.defineProperties(DesktopSubMenuItemDefault, {}); 363 Object.defineProperties(DesktopSubMenuItemDefault.prototype, { 364 expandedClass: constant(expandedClass), 365 expandedSelector: constant(expandedSelector), 366 isExpanded: getterSetter(function () { 367 return this.el.classList.contains(this.expandedClass); 368 }), 369 expand: constant(function () {
370 this.root.markOpened(); 371 // Set submenu visible if there is one 372 this.$el.addClass(this.expandedClass); 373 // echo up the tree 374 this.$a.parents('li').addClass(this.expandedClass); 375 }), 376 contract: constant(function () { 377 this.$el 378 .removeClass(this.expandedClass) 379 .find(this.expandedSelector) 380 .removeClass(this.expandedClass); 381 }), 382 clearExpand: constant(function () { 383 this.root.closeAll(); 384 }), 385 }); 386 })(); 387 388 // Provide a mobile view 389 (function MobileView($desktopContactForm) { 390 var $mobileSection; 391 /** 392 * @typedef MobileSectionClusterItem 393 * @property {JQuery} $el - Element to be inserted 394 * @property {Node} source 395 * 396 * @type MobileSectionClusterItem[]*/ 397 var mobileSectionCluster = []; 398 var mobileClass = 'mobile-controls'; 399 var $desktopNav = $( 400 '.section-navigation-mobile, .section-navigation-mobile--no-hide' 401 ) 402 .find('.component.navigation') 403 .find('.navigation-a, .navigation-b, .navigation-c') 404 .first(); 405 var $desktopPhone = $('.section-phone-mobile .phone__container') 406 .find('.phone__number') 407 .first(); 408 var $desktopMap = $('.map__container').first(); 409 410 if ( 411 [$desktopNav, $desktopPhone, $desktopContactForm, $desktopMap].every( 412 function isEmpty($el) { 413 return $el.length === 0; 414 } 415 ) 416 ) { 417 return; 418 } 419 420 if ($desktopNav.length) { 421 $mobileSection = $( 422 '<div class="' + mobileClass + ' d-lg-none sticky-top"></div>' 423 ).prependTo($body); 424 425 (function MmenuButton() { 426 var $mobileNav, $menuButton, mmenuAPI; 427 $mobileNav = $desktopNav.clone(); 428 429 // Remove any buttons 430 $mobileNav.find('button').remove(); 431 432 // Strip call classes 433 $mobileNav 434 .removeClass() 435 .addClass('d-lg-none') 436 .find('ul, li, a') 437 .removeClass(); 438 $desktopNav.addClass('d-none d-lg-block'); 439 440 // Build the menu button 441 $menuButton = $( 442 '<button type="button" title="Show Navigation Menu">' + 443 '<i aria-hidden="true" class="icon icon-bars"></i><span> Menu</span>' + 444 '</button>' 445 ).appendTo($mobileSection); 446 447 // Initialize MMenu Plugin 448 $mobileNav.mmenu({ 449 extensions: ['pagedim-black'], 450 counters: true, 451 navbars: [ 452 { 453 position: 'top', 454 content: ['prev', 'title', 'close'], 455 }, 456 { 457 position: 'top', 458 content: ['searchfield'], 459 }, 460 ], 461 }); 462 463 mmenuAPI = $mobileNav.data('mmenu'); 464 465 // Bind the menu button to the API 466 $menuButton.on('click', function () { 467 mmenuAPI.open(); 468 }); 469 })(); 470 } 471 472 function mobileLinkTemplate(classSubName, description, icon, href) { 473 var $el = $( 474 '<div class="' + mobileClass + '__' + classSubName + '"></div>' 475 ); 476 var $link = $( 477 '<a title="' + 478 description + 479 '" class="btn btn-link">' + 480 ('<i class="icon ' + 481 icon + 482 '" aria-hidden="true"></i>' + 483 '<span class="sr-only">' + 484 description + 485 '</span>') + 486 '</a>' 487 ) 488 .attr('href', href) 489 .appendTo($el); 490 return { 491 $el: $el, 492 $link: $link, 493 }; 494 } 495 496 if ($desktopPhone.length) { 497 mobileSectionCluster.push( 498 (function PhoneLink($selector) { 499 var sectionId = getPLESection($selector).attr('id') || ''; 500 // Valid separators are (-.), valid digits are 0-9 501 // See: https://tools.ietf.org/html/rfc3966#section-3 'global-number-digits' 502 var tel = $selector 503 .text() 504 .trim() 505 .replace(/([^0123456789\-.()])/g, ''); 506 var template = mobileLinkTemplate( 507 'phone', 508 'Call', 509 'icon-phone', 510 'tel:+' + tel 511 ); 512 return { 513 $el: template.$el, 514 source: $selector.get(0), 515 }; 516 })($desktopPhone) 517 ); 518 } 519 520 function mobileAnchorLink($selector, classSubName, description, icon) { 521 var sectionId = getPLESection($selector).attr('id') || ''; 522 var template = mobileLinkTemplate( 523 classSubName, 524 description, 525 icon, 526 '#' + sectionId 527 ); 528 template.$link.on('click', scrollTo($selector)); 529 return { 530 $el: template.$el, 531 source: $selector.get(0), 532 }; 533 } 534 535 if ($desktopMap.length) { 536 mobileSectionCluster.push( 537 mobileAnchorLink( 538 $desktopMap, 539 'location', 540 'Location', 541 'icon icon-location-arrow' 542 ) 543 ); 544 } 545 546 if ($desktopContactForm.length) { 547 mobileSectionCluster.push( 548 mobileAnchorLink( 549 $desktopContactForm, 550 'contact-us', 551 'Contact Us', 552 'icon-envelope-o' 553 ) 554 ); 555 } 556 557 if (mobileSectionCluster.length) { 558 mobileSectionCluster 559 .sort(function (a, b) { 560 return a.source.compareDocumentPosition(b.source) & 561 Node.DOCUMENT_POSITION_PRECEDING 562 ? 1 563 : -1; 564 }) 565 .reduce(function ($target, value) { 566 return $target.append(value.$el); 567 }, $('<div class="' + mobileClass + '__quick-links"></div>')) 568 .appendTo($mobileSection); 569 } 570 })($contactForm); 571 572 // Add Browserlock 573 (function BrowserLock($target) { 574 if ($target.length) { 575 // Create ContactForm lock 576 var $contactFormLock = $('<div>').addClass('contactform-lock'); 577 578 // Add ContactForm click event 579 $contactFormLock.on('click', scrollTo($target)); 580 581 // Draw browser lock containers, prepend to body
582 var $lockContainer = $('<div>') 583 .addClass('browser-lock') 584 .append($contactFormLock); 585 586 $('body').prepend($lockContainer); 587 } 588 })($contactForm); 589 590 // Preview link fix 591 (function cleanUpRedactorLinks() { 592 // Check if we're in an iFrame or not (editor mode or preview link) 593 if (self != top) return; 594 595 var link = $('link[rel=canonical]').attr('href'); 596 if (link != undefined) { 597 var parts = link.split('/'), 598 index = parts.indexOf('my.martindalenolo.com'); 599 if (index >= 0) { 600 var siteId = parts[index + 1]; 601 if (!siteId) return; 602 603 var $links = $( 604 'div[data-component-name=editable] a[data-source-type=my-pages]' 605 ); 606 if ($links == undefined || $links.length == 0) return; 607 608 $links.each(function () { 609 var currentLink = $(this).attr('href'); 610 611 // Check for edge-case of absolute my-page 612 var index = currentLink.split('/').indexOf(siteId); 613 if (index >= 0) return; 614 615 var newLink = '/' + siteId + currentLink; 616 $(this).attr('href', newLink); 617 }); 618 } 619 } 620 })(); 621 622 (function setBrowserlock() { 623 var rawSettings = $('#ple-data-json').text(); 624 var settings = JSON.parse(rawSettings); 625 var browserlockSettings = settings.fixedSection; 626 627 //#SMBWMGR-8501 this check can be removed after merging - /editor/merge_requests/1922 628 if (typeof browserlockSettings !== 'undefined') { 629 var $browserLockContainer = $('#' + browserlockSettings.id).find( 630 '.ple__browserlock-modules' 631 ); 632 var $browserLockModules = $browserLockContainer.find('> .row .row'); 633 634 if ( 635 browserlockSettings.spacing.space == 'custom' && 636 browserlockSettings.spacing.offsetDistance && 637 parseInt(browserlockSettings.spacing.offsetDistance) != NaN 638 ) { 639 $browserLockModules.each(function (index, element) { 640 $(element).css({ 641 marginBottom: browserlockSettings.spacing.offsetDistance, 642 }); 643 }); 644 } 645 646 if (browserlockSettings.placement.place != null) { 647 switch (browserlockSettings.placement.place) { 648 case 'center-right': 649 $browserLockContainer.css({ 650 top: '50%', 651 transform: 'translateY(-50%)', 652 }); 653 break; 654 655 case 'bottom-right': 656 $browserLockContainer.css({ 657 top: 'auto', 658 }); 659 660 if ( 661 parseInt(browserlockSettings.placement.offsetDistance) != NaN && 662 !browserlockSettings.placement.useDefaultOffset 663 ) { 664 $browserLockContainer.css({ 665 bottom: browserlockSettings.placement.offsetDistance, 666 }); 667 } 668 break; 669 670 case 'top-right': 671 default: 672 if ( 673 parseInt(browserlockSettings.placement.offsetDistance) != NaN && 674 !browserlockSettings.placement.useDefaultOffset 675 ) { 676 $browserLockContainer.css({ 677 top: browserlockSettings.placement.offsetDistance, 678 }); 679 } 680 break; 681 } 682 } 683 } else { 684 console.log('browserlock Settings is undefinded'); 685 } 686 })(); 687 688 (function backToTop() { 689 var $bttButton = $('.ple__back-to-top'); 690 var activeClass = 'active'; 691 var showPoint = 400; 692 693 $bttButton.on('click', function (event) { 694 event.preventDefault(); 695 696 $([document.documentElement, document.body]).animate( 697 { 698 scrollTop: 0, 699 }, 700 1000 701 ); 702 }); 703 704 $(window).scroll(function () { 705 var window_x = $(window).scrollTop(); 706 if (window_x >= showPoint) { 707 $bttButton.addClass(activeClass); 708 } else { 709 $bttButton.removeClass(activeClass); 710 } 711 }); 712 })(); 713 714 (function mobileHeader() { 715 function mobileHeaderInit() { 716 var $mhContainer = $('.mobileHeader-container'), 717 mhHeaight = $mhContainer.height(), 718 $navButton = $('#mobileHeaderNavBtn'), 719 $navMenu = $('#mobileHeaderNav'), 720 $homeIcon = $('.mobileHeader-homeIcon'), 721 $formIcon = $('.formIconLink'), 722 $mapIcon = $('.locIconLink'), 723 $phoneIcon = $('.phoneIconLinkExpand'), 724 $mapContainer = $('.map__container').first(), 725 $formContainer = $('.form__container').first(), 726 $locList = $('.location-list'), 727 $pleMSticky = $('.ple_module_sticky'), 728 navAPI; 729 730 // if there is no form module in the view target the contactform module 731 if (!$formContainer.length) 732 $formContainer = $('.contactform__container').first(); 733 734 // if sticky module is present set top space to the first elem for the mobileHeader 735 if ($pleMSticky.length) { 736 var $pleMStickEl = $pleMSticky.first().find('.container'); 737 $(window).resize(function () { 738 mhHeaight = $mhContainer.height(); 739 $pleMStickEl.css('padding-top', mhHeaight); 740 }); 741 } 742 743 if ($navMenu.children().length) { 744 // init mMenu 745 $navMenu.mmenu({ 746 extensions: ['pagedim-black'], 747 counters: true, 748 navbars: [ 749 { 750 position: 'top', 751 content: ['prev', 'title', 'close'], 752 }, 753 ], 754 }); 755 // bind menu button
756 navAPI = $navMenu.data('mmenu'); 757 $navButton.on('click', function () { 758 navAPI.open(); 759 }); 760 } 761 762 // handle click events for the icons 763 $formContainer.length 764 ? $formIcon.click(scrollToEl($formContainer)) 765 : $formIcon.fadeOut(); 766 $mapContainer.length 767 ? $mapIcon.click(scrollToEl($mapContainer)) 768 : $mapIcon.fadeOut(); 769 $phoneIcon.click(function () { 770 $locList.addClass('expand'); 771 }); 772 $('.mobileHeader-locWrap') 773 .find('.icon-times') 774 .click(function () { 775 $locList.removeClass('expand'); 776 }); 777 778 // replace the mm title with the home icon 779 if ($homeIcon.length) { 780 $('.mobileHeader-homeIcon .mm-homeIcon').insertBefore( 781 $('#mobileHeaderNav .mm-navbar-top .mm-title') 782 ); 783 } 784 785 // set the section bg class 786 if ($mhContainer.is('[class*=section__bg]')) { 787 var classList = $mhContainer.prop('classList'); 788 $.each(classList, function (index, item) { 789 if (item.startsWith('section__bg')) { 790 $navMenu.addClass(item); 791 } 792 }); 793 } 794 795 $(window).load(function () { 796 alignLogo(); 797 }); 798 799 $(window).resize(function () { 800 alignLogo(); 801 }); 802 } 803 804 // align logo with if only navigation is present or only one icon is present on the right hand side 805 function alignLogo() { 806 if ( 807 !$('.mobileHeader-form').length && 808 !$('.mobileHeader-location').length && 809 !$('.mobileHeader-phone').length && 810 $('#mobileHeaderNavBtn').length 811 ) { 812 var hamburgerMenuWidth = $( 813 '.mobileHeader-navigation #mobileHeaderNavBtn' 814 ).outerWidth(true); 815 $('.mobileHeader-logo').css('margin-right', hamburgerMenuWidth); 816 } 817 if ( 818 ($('.mobileHeader-form').length || 819 $('.mobileHeader-location').length || 820 $('.mobileHeader-phone').length) && 821 !$('#mobileHeaderNavBtn').length 822 ) { 823 var totalWidthIcons = 824 $('.mobileHeader-form').width() + 825 $('.mobileHeader-location').width() + 826 $('.mobileHeader-phone').width(); 827 if (totalWidthIcons < 46) { 828 $('.mobileHeader-logo').css('margin-left', totalWidthIcons); 829 } 830 } 831 } 832 833 function scrollToEl($el) { 834 return function () { 835 var $moduleSticky = $('.ple_module_sticky'), 836 moduleStickyHeight = 0; 837 if ($moduleSticky.length) 838 $moduleSticky.each(function () { 839 moduleStickyHeight += $(this).find('.container').outerHeight(true); 840 }); 841 if (moduleStickyHeight == 0) 842 moduleStickyHeight = $('.mobileHeader-container').height(); 843 $('html, body').animate( 844 { scrollTop: $el.offset().top - moduleStickyHeight }, 845 'slow' 846 ); 847 }; 848 } 849 850 if ($('.mobileHeader-container').length && ($('.section-navigation').length || $('.section-partial nav').length)) mobileHeaderInit(); 851 })(); 852 }); 853})(); 854 855$(document).ready(function () { 856 featuredBlocksAAccordion(); 857 bluredBladeBG(); 858 staffOverlapped(); 859 galleryTitle(); 860 navigationVisibility(); 861 bannerOverImage(); 862 bannerAboveImage(); 863 bannerFAbstractShape(); 864 footerParallax(); 865 bladeParallax(); 866 bannerTitleHighlight(); 867 partialTestimonialsSlider(); 868 fbFullImage(); 869}); 870 871$(window).load(function () { 872 navADropDown2(); 873 bannerDSwoop(); 874 bladeNarrowSbg(); 875}); 876 877$(window).resize(function () { 878 navADropDown2(); 879}); 880 881function navADropDown2() { 882 /* this will enable the hover submenu when in edit mode */ 883 var isEditMode = $('body').hasClass('isEditor'); 884 885 if (isEditMode) { 886 var $navSection = $("nav[class^='navigation-']"), 887 zindex = 110; 888 889 if ($navSection.length) { 890 $navSection.closest('.section--inner').addClass('fix-hover'); 891 892 $navSection.each(function (index) { 893 $(this).closest('.section-base-container').css({ 894 'z-index': --zindex, 895 }); 896 }); 897 } 898 } 899 900 $('.navigation-a').on( 901 'mouseover', 902 '.navigation__list--default li.has-drop-down', 903 function () { 904 $(this).parent().css('overflow', 'visible'); 905 } 906 ); 907} 908 909function bannerDSwoop() { 910 $('.section.banner-d-swoop .banner-d .banner__text-overlay--triangle').html( 911 '<svg preserveAspectRatio="none" viewBox="0 0 230 640"><path d="M19.0476 320C19.9223 175.303 175 60 200 0H0V640H192.381C175 580 18.1822 463.173 19.0476 320Z"/></svg>' 912 ); 913} 914
915function bannerFAbstractShape() { 916 $('.section.banner-f-abstract-shape .banner-f .banner__image').append( 917 '<svg viewBox="0 0 485 604" preserveAspectRatio="none"><path d="M483.517 276.495C478.395 332.998 417.997 361.109 384.893 407.184C338.52 471.726 330.461 573.271 254.203 595.653C170.328 620.271 61.9045 589.488 14.9268 515.771C-30.1316 445.066 46.0074 360.199 50.8125 276.495C55.053 202.625 -3.38703 122.467 40.9069 63.1982C86.8067 1.78029 178.409 -7.24325 254.203 4.34036C320.879 14.5304 367.485 68.1701 410.947 119.751C449.514 165.523 488.921 216.885 483.517 276.495Z"/></svg>' 918 ); 919} 920 921function bladeNarrowSbg() { 922 $('.section.blade-narrow-sbg .blade__text-media--swapped') 923 .closest('.section') 924 .addClass('blade__text-media--swapped'); 925} 926 927function featuredBlocksAAccordion() { 928 $('.section.fb-grid-a-accordion .featuredblock__wrap').each(function () { 929 $(this).append('<div class="featuredblock__accordion"></div>'); 930 931 var fbTitleWrapper = $(this).find('.featuredblock-image-title-wrapper'); 932 var fbAccordion = $(this).find('.featuredblock__accordion'); 933 var fbContent = $(this).find('.featuredblock__content'); 934 var fbSubMenu = $(this).find('.featuredblock__sub-menu'); 935 var fbCTA = $(this).find('.featuredblock__cta'); 936 var hasIcon = fbTitleWrapper.has('.featuredblock__icon').length; 937 var hasImg = fbTitleWrapper.has('.featuredblock__image').length; 938 939 fbAccordion.append(fbContent, fbSubMenu, fbCTA); 940 fbTitleWrapper.click(function (e) { 941 e.preventDefault(); 942 $(this).toggleClass('expanded'); 943 fbAccordion.slideToggle(); 944 }); 945 946 if (hasIcon == 0 && hasImg == 0) { 947 fbAccordion.addClass('no-margin'); 948 } 949 }); 950} 951 952function bluredBladeBG() { 953 $('.section.blade-background-blur').each(function () { 954 let imgHolder = $(this).find('.blade__media'), 955 img = imgHolder.find('img'), 956 imgSrc = img.attr('src'); 957 if (!!imgHolder.length && !!img.length && !!imgSrc) { 958 imgHolder.css({ 959 backgroundImage: 'url(' + imgSrc + ')', 960 backgroundSize: 'cover', 961 backgroundPosition: '50% 50%', 962 backgroundRepeat: 'no-repeat', 963 }); 964 img.remove(); 965 } 966 }); 967} 968function staffOverlapped() { 969 let maxHeight = 0; 970 $('.section.staff-overlapped-card .staff-member').each(function () { 971 //for image replace to bg 972 let imgHolder = $(this).find('.staff-member__image-wrapper'), 973 img = imgHolder.find('img'), 974 imgSrc = img.attr('src'), 975 textHolder = $(this).find('.staff-member__text'); 976 if (!!imgHolder.length && !!img.length && !!imgSrc) { 977 imgHolder.css({ 978 backgroundImage: 'url(' + imgSrc + ')', 979 backgroundSize: 'cover', 980 backgroundPosition: '50% 50%', 981 backgroundRepeat: 'no-repeat', 982 }); 983 img.remove(); 984 } 985 }); 986} 987 988function galleryTitle() { 989 var galTitle = $('.award-banner-1 .gallery .gallery__title').text(); 990 $('.award-banner-1 .gallery .gallery__title').replaceWith('<h1></h1>'); 991 $('.award-banner-1 .gallery h1') 992 .text(galTitle) 993 .addClass('gallery__title component__title'); 994} 995 996function navigationVisibility() { 997 var mhEnabled = $('.mobileHeader-container').length; 998 if (mhEnabled) { 999 var tabletFlag = $('#tabletHeaderEnabledFlag').val(), 1000 $navSection = $('.section-navigation .navigation'); 1001 if (tabletFlag == 1) { 1002 $navSection.addClass('d-none d-lg-block'); 1003 } else { 1004 $navSection.addClass('d-none d-md-block'); 1005 } 1006 } 1007} 1008 1009function bannerOverImage() { 1010 'use strict'; 1011 let banner = $('.banner-f-title-over-image'); 1012 banner.each(function () { 1013 let curBanner = $(this), 1014 curItems = curBanner.find('.banner__item'); 1015 curItems.each(function () { 1016 let cur = $(this), 1017 curTextImage = cur.find('.banner__text-wrapper, .banner__image-wrapper'), 1018 imageTextHolder = "<div class='holder'/>"; 1019 curTextImage.wrapAll(imageTextHolder); 1020 }); 1021 }); 1022} 1023function bannerAboveImage() { 1024 'use strict'; 1025 let banner = $('.banner-a-title-above'); 1026 banner.each(function () { 1027 let curBanner = $(this), 1028 curText = curBanner.find('.banner__title, .banner__tc-divider'), 1029 curCta = curBanner.find('.banner__subtitle, .banner__cta-wrapper'), 1030 ctaHolder = "<div class='cta__holder'/>", 1031 textHolder = "<div class='text__holder'/>"; 1032 curText.wrapAll(textHolder); 1033 curCta.wrapAll(ctaHolder); 1034 }); 1035} 1036 1037// This function implements a parallax effect for the footer. 1038function footerParallax() { 1039 'use strict'; 1040 let target = document.querySelector('.footer-parallax'); 1041 if (!target) { 1042 // If the target element with class 'footer-parallax' is not found, stop execution. 1043 //console.error('.footer-parallax not find'); 1044 return; 1045 } 1046 1047 // Apply smooth transition effect to background position change. 1048 target.style.transition = 'background-position .5s'; 1049 1050 // Options for IntersectionObserver 1051 const options = { 1052 root: null, 1053 rootMargin: '0px', 1054 threshold: [0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1], 1055 }; 1056 1057 // Callback function to handle changes in the intersection of the target element. 1058 let callback = function (entries, observer) {
1059 entries.forEach((entry) => { 1060 // Calculate the threshold value (intersectionRatio) for each entry. 1061 const thresholdValue = entry.intersectionRatio; 1062 // Adjust the background position based on the threshold value to create the parallax effect. 1063 entry.target.style.backgroundPosition = `50% ${50 + thresholdValue * 40}%`; 1064 }); 1065 }; 1066 1067 // Create an IntersectionObserver instance with the defined callback and options. 1068 const observer = new IntersectionObserver(callback, options); 1069 1070 // Start observing the target element. 1071 observer.observe(target); 1072} 1073 1074function bladeParallax() { 1075 let target = document.querySelector('.blade-parallax'); 1076 if (!target) { 1077 //console.error('.blade-parallax not find'); 1078 return; // Stop if class not find 1079 } 1080 const options = { 1081 root: null, 1082 rootMargin: '0px', 1083 threshold: [ 1084 0, 0.25, 0.3, 0.45, 0.5, 0.55, 0.6, 0.65, 0.7, 0.75, 0.8, 0.85, 0.9, 0.95, 1, 1085 ], 1086 }; 1087 1088 let callback = function (entries, observer) { 1089 entries.forEach((entry) => { 1090 const thresholdValue = entry.intersectionRatio; 1091 const target = entry.target.querySelector('.blade__media'); 1092 target.style.transition = 'transform .5s'; 1093 const transformValue = 100 * (1 - thresholdValue); 1094 target.style.transform = `translateY(${transformValue}px)`; 1095 }); 1096 }; 1097 1098 const observer = new IntersectionObserver(callback, options); 1099 observer.observe(target); 1100} 1101 1102function bannerTitleHighlight() { 1103 'use strict'; 1104 // Select the target element with the class '.section.banner-a-highlighted-title' 1105 let target = document.querySelector('.section.banner-a-highlighted-title'); 1106 if (!target) { 1107 // If the target element is not found, log an error and return 1108 //console.error('.blade-parallax not find'); 1109 return; // Stop if class not found 1110 } 1111 1112 // Define options for the IntersectionObserver 1113 const options = { 1114 root: null, // Use the viewport as the root 1115 rootMargin: '0px', // No margin around the root 1116 threshold: [0.75], // Trigger callback when 75% of the target is visible 1117 }; 1118 1119 // Define the callback function for the IntersectionObserver 1120 let callback = function (entries, observer) { 1121 // Iterate over each entry in the observer 1122 entries.forEach((entry) => { 1123 // If the target is intersecting with the viewport 1124 if (entry.isIntersecting) { 1125 // Add the 'highlighted' class to the target element 1126 entry.target.classList.add('highlighted'); 1127 } else { 1128 // If the target is not intersecting, remove the 'highlighted' class 1129 entry.target.classList.remove('highlighted'); 1130 } 1131 }); 1132 }; 1133 1134 // Create a new IntersectionObserver instance with the defined callback and options 1135 const observer = new IntersectionObserver(callback, options); 1136 1137 // Select all elements with the class '.banner__title' within the target element 1138 let targets = target.querySelectorAll('.banner__title'); 1139 // Iterate over each selected target element 1140 targets.forEach((target) => { 1141 // Observe each target element with the IntersectionObserver 1142 observer.observe(target); 1143 // Wrap text content of banner__title in span 1144 let titleText = target.textContent.trim(); 1145 target.innerHTML = `<span>${titleText}</span>`; 1146 // Add height to banner__title 1147 target.style.height = `${target.offsetHeight}px`; 1148 }); 1149} 1150 1151function partialTestimonialsSlider() { 1152 'use strict'; 1153 let testimonialsPartial = $( 1154 '.partial-testimonials-cta .js-testimonials-layout-settings.flexslider' 1155 ); 1156 1157 // Check if testimonialsPartial exists 1158 if (!testimonialsPartial) { 1159 return; // Exit the function if testimonialsPartial is not found 1160 } 1161 1162 // Function to set itemWidth and itemMargin based on window width 1163 function setItemSettings() { 1164 if (window.innerWidth < 768) { 1165 // Example breakpoint, adjust as needed 1166 return { 1167 itemWidth: 75, // Set itemWidth to 75 for smaller screens 1168 itemMargin: 5, // Set itemMargin to 5 for smaller screens 1169 }; 1170 } else { 1171 return { 1172 itemWidth: 98, // Set itemWidth to 98 for larger screens 1173 itemMargin: 22, // Set itemMargin to 22 for larger screens 1174 }; 1175 } 1176 } 1177 1178 // Re-initialize flexslider for testimonialsPartial 1179 testimonialsPartial.flexslider({ 1180 animation: 'slide', // Set animation type to slide 1181 controlNav: false, // Hide navigation bullets 1182 directionNav: false, // Hide direction navigation arrows 1183 maxItems: 5, // Maximum number of items visible in the slider 1184 ...setItemSettings(), // Spread the returned object from setItemSettings function 1185 keyboard: false, // Disable keyboard navigation 1186 slideshow: false, // Disable slideshow 1187 }); 1188 1189 // Add event listener for window resize to update itemWidth and itemMargin dynamically 1190 $(window).on('resize', function () { 1191 const { itemWidth, itemMargin } = setItemSettings(); 1192 testimonialsPartial.flexslider('setOption', 'itemWidth', itemWidth); 1193 testimonialsPartial.flexslider('setOption', 'itemMargin', itemMargin); 1194 }); 1195} 1196 1197// Function fbFullImage() 1198// This function moves specific elements inside each .featuredblock__item element inside .featuredblock__wrap, 1199// creating a container with the class .featuredblock__content--holder and moving selected elements into it. 1200function fbFullImage() { 1201 'use strict'; 1202 // Get the .section.fb-grid-a-full-image element 1203 let fbHolder = document.querySelector('.section.fb-grid-a-full-image'); 1204 // Check if fbHolder exists 1205 if (!fbHolder) { 1206 return; // If fbHolder doesn't exist, exit the function 1207 } 1208 // Get all .featuredblock__item elements inside fbHolder 1209 let fbItems = fbHolder.querySelectorAll('.featuredblock__item'); 1210 // Iterate through each .featuredblock__item element
1211 fbItems.forEach(function (fbItem) { 1212 // Get all inner elements we want to move 1213 let itemInnerItems = fbItem.querySelectorAll( 1214 '.featuredblock__icon, .featuredblock__title, .featuredblock__content, .featuredblock__sub-menu, .featuredblock__cta' 1215 ); 1216 // Get the .featuredblock__wrap element inside the current fbItem 1217 let featuredblockWrap = fbItem.querySelector('.featuredblock__wrap'); 1218 // Create a new div element with the class .featuredblock__content--holder 1219 let itemContentHolder = document.createElement('div'); 1220 itemContentHolder.classList.add('featuredblock__content--holder'); 1221 // Iterate through each inner item and append it to itemContentHolder 1222 itemInnerItems.forEach(function (innerItem) { 1223 itemContentHolder.appendChild(innerItem); 1224 }); 1225 // Append itemContentHolder inside featuredblockWrap 1226 featuredblockWrap.appendChild(itemContentHolder); 1227 }); 1228}
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.