1/** 2 * Footer script migrated from the retired "Custom Codes" plugin (custom_public.js, save #364). 3 * Changes vs. the plugin copy: cl() is a no-op (was console.log), scrollToLinks guards $("#") (the 4 * only call that depended on jQuery Migrate, removed in P6), and the page checks accept 5 * slug-based body classes (page-dining-and-social, page-fitness-spa, home) added by 6 * includes/assets.php as alternates to page-id-11 / page-id-12 / page-template-page-home. 7 * Depends on jQuery, assets/js/vendors.min.js (gsap, ScrollTrigger, video.js, $.scrollLock, lazysizes) 8 * and the theme dist bundle (slick, magnificPopup). 9 */ 10jQuery(document).ready(function($){ 11 var $win = $(window), 12 $doc = $(document), 13 $html = $("html"), 14 $body = $("body"), 15 $header = $("header.header"), 16 $nav = $header.find("nav"), 17 $navBtn = $header.find(".menu-toggle"), 18 $footer = $("footer.footer"), 19 $siteContent = $(".main"), 20 isMobile = /Android|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent), 21 controller,//NEED TO REMOVE SCOLLMAGIC DEPENDENCIES 22 events = eventsObj(); 23 var winWidth = $win.width(), 24 winHeight = $win.height(), 25 docHeight = $doc.height(), 26 scrollY = $win.scrollTop(); 27 28 29 //----------------------------------------------------------------------- 30 //-- MODULES 31 //----------------------------------------------------------------------- 32 var modules = { 33 //--------------------------------- 34 //-- PAGES 35 //--------------------------------- 36 homePage: function() { 37 if (!$body.hasClass("page-template-page-home") && !$body.hasClass("home")) { return; } 38 }, 39 wellnessPage: function() { 40 if (!$body.hasClass("page-id-12") && !$body.hasClass("page-fitness-spa")) { return; } 41 42 $header.find(".scroll-to a").on("click", scrollToSection); 43 44 45 function scrollToSection(e) { 46 e.preventDefault(); 47 var href = $(this).attr("href").replace("/wellness", ""), 48 $section = $(href); 49 50 if ($section.length) { 51 events.emit("scroll_to_link_click"); 52 $html.add($body).animate({ 53 scrollTop: $section.offset().top 54 }, 1000); 55 } 56 } 57 58 }, 59 fitnessSpa: function() { 60 if (!$body.hasClass("page-id-12") && !$body.hasClass("page-fitness-spa")) { return; } 61 62 fitnessGallery(); 63 64 function fitnessGallery() { 65 var $sec = $siteContent.find("#fitness-center"), 66 $galleryBtn = $sec.find(".js-fitness-gallery-trigger"), 67 $jsonCnt = $siteContent.find(".fitness-gallery-json-cnt"), 68 galleryItems = getGalleryItems(), 69 $mfpCnt = null;cl("gallery items", galleryItems); 70 71 var mfpGallery = $galleryBtn.magnificPopup({ 72 items: galleryItems, 73 type: 'image', 74 removalDelay: 300, 75 mainClass: "mfp-fade", 76 closeMarkup: '<button title="Close (Esc)" type="button" class="mfp-close"><span></span>Back to gallery</button>', 77 gallery: { 78 enabled:true, 79 navigateByImgClick: false 80 }, 81 callbacks: { 82 open: function() {//cl("gallery open"); 83 $mfpCnt = $(".mfp-container"); 84 setupGalleryNav(); 85 }, 86 change: function() {//cl("gallery change"); 87 setupGalleryNav(); 88 }, 89 close: function() { 90 $mfpCnt = null; 91 } 92 }, 93 }); 94 95 function setupGalleryNav() { 96 if ($mfpCnt === null) { return; }
97 var $nav = $mfpCnt.find(".mfp-arrow"), 98 currentIndex = $.magnificPopup.instance.index, 99 prevItem = getPrevNext("prev", currentIndex), 100 nextItem = getPrevNext("next", currentIndex), 101 html = `<a href="#" class="section__image image-fit" style="position:absolute;"><img src="{{src}}" srcset="{{srcset}}" /></a>`;//cl("curr index", currentIndex);cl("prev",prevItem);cl("next", nextItem); 102 103 $nav.filter(".mfp-arrow-left").empty().html(html.replace(/{{src}}/g, prevItem.src).replace(/{{srcset}}/g, prevItem.srcset)); 104 $nav.filter(".mfp-arrow-right").empty().html(html.replace(/{{src}}/g, nextItem.src).replace(/{{srcset}}/g, nextItem.srcset)); 105 } 106 function getPrevNext(direction, index) { 107 var prevNextIndex; 108 109 if (direction === "prev") { 110 prevNextIndex = (index == 0) ? galleryItems.length - 1 : pI(index) - 1; 111 } 112 else { 113 prevNextIndex = (index == (galleryItems.length - 1)) ? 0 : pI(index) + 1; 114 } 115 return galleryItems[prevNextIndex]; 116 } 117 function getGalleryItems() { 118 var $jsonItems = $jsonCnt.find(".fitness-gallery-item-json"), 119 gallery = []; 120 121 $jsonItems.each(function() { 122 var image = JSON.parse($(this).html()); 123 gallery.push({ src: image.src, srcset: image.srcset }); 124 }); 125 126 return gallery; 127 } 128 } 129 }, 130 diningSocial: function() { 131 if (!$body.hasClass("page-id-11") && !$body.hasClass("page-dining-and-social")) { return; } 132 133 featuresSlider(); 134 135 function featuresSlider() { 136 var $sec = $siteContent.find("section.section-features"), 137 $imgSlider = $sec.find(".features-img-slider"), 138 $contentSlider = $sec.find(".features-tabs-slider"), 139 $tabLinks = $sec.find(".tab-title"), 140 autoplaySpeed = pI($imgSlider.attr("data-speed")) || 3000; 141 142 //Set tab link 143 $tabLinks.first().addClass("active"); 144 //Init sliders 145 $imgSlider.slick({ 146 infinite: true, 147 speed: 500, 148 fade: true, 149 cssEase: 'linear', 150 appendArrows: $imgSlider.siblings('.slider__pages').find('.slider-nav-cnt'), 151 asNavFor: $contentSlider, 152 autoplay: false, 153 //autoplayspeed: autoplaySpeed, 154 }); 155 $contentSlider.slick({ 156 infinite: true, 157 speed: 500, 158 fade: true, 159 cssEase: 'linear', 160 arrows: false, 161 asNavFor: $imgSlider 162 }); 163 //Change tab on slider change 164 $imgSlider.on("beforeChange", function() { 165 $tabLinks.removeClass("active"); 166 }); 167 $imgSlider.on("afterChange", function() { 168 var activeIndex = $imgSlider.slick("slickCurrentSlide");//cl("slick after change", activeIndex); 169 $tabLinks.eq(activeIndex).addClass("active"); 170 }); 171 //Change slider on tab link click 172 $tabLinks.on("click", function() { 173 $imgSlider.slick("slickGoTo", $(this).index()); 174 }); 175 } 176 }, 177 178 //--------------------------------- 179 //-- SECTIONS 180 //--------------------------------- 181 heroVideoSections: function() { 182 var $sec = $(".hero-video"); 183 if (!$sec.length) { return; } 184 185 var $vidCnt = $sec.find(".video-cnt"), 186 poster = $vidCnt.attr("data-poster"), 187 video = (mq("landscape")) ? $vidCnt.attr("data-video-h") : $vidCnt.attr("data-video-v"), 188 html = `<video id="hero-video" class="video-js" controls preload="auto" poster="${poster}" muted playsinline autoplay> 189 <source src="${video}" type="video/mp4"> 190 <p class="vjs-no-js"> 191 To view this video please enable JavaScript, and consider upgrading to a 192 web browser that 193 <a href="https://videojs.com/html5-video-support/" target="_blank"> 194 supports HTML5 video 195 </a> 196 </p> 197 </video>`,
198 buttons = `<button class="pause-btn js-pause-play active" title="pause video"><span class="screenreader">Pause Video</span></button> 199 <button class="play-btn js-pause-play" title="pause video"><span class="screenreader">Pause Video</span></button>`; 200 201 $vidCnt.append(html); 202 var options = { autoplay: 'muted', loop: true , controls: false }; 203 var player = videojs('hero-video', options, onPlayerReady); 204 205 $sec.append(buttons).on("click", ".js-pause-play", togglePausePlay); 206 207 function onPlayerReady() {//videojs.log('Your player is ready!'); 208 $vidCnt.removeClass("vis-h"); 209 var promise = this.play(); 210 211 if (promise !== undefined) { 212 promise.then(function() { 213 // Autoplay started! 214 }).catch(function(error) {cl("video autoplay error", error); 215 // Autoplay was prevented. 216 }); 217 } 218 219 this.on('ended', function() { 220 //videojs.log('video ended'); 221 }); 222 } 223 function togglePausePlay() { 224 var $this = $(this), 225 isPause = $this.hasClass("pause-btn"); 226 if (isPause) 227 player.pause(); 228 else 229 player.play(); 230 231 $sec.find(".js-pause-play").toggleClass("active"); 232 } 233 }, 234 jsSliders: function() { 235 var $sliders = $(".js-slider, .js-slider-alt").find(".slider__slides"); 236 237 $sliders.each(function() { 238 var $slider = $(this), 239 $titles = $slider.siblings(".slider__pages").find("h3"); 240 241 $slider.on("beforeChange", removeCurrent); 242 $slider.on('afterChange', updateTitles); 243 $titles.on("click", changeSlide); 244 245 function removeCurrent() { 246 $titles.removeClass("is-current"); 247 } 248 function updateTitles(event, slick, currentSlide) { 249 $titles.eq(currentSlide).addClass("is-current"); 250 } 251 function changeSlide() { 252 if (mq("min-width:1024px")) { 253 $slider.slick('slickGoTo', $(this).index() - 1); 254 } 255 } 256 }); 257 }, 258 259 accordionsMenu: function() { 260 var $sec = $siteContent.find("section.section-menu"), 261 $accordions = $sec.find(".table-menu"), 262 $accordionsDinning = $sec.find(".list-menu"); 263 264 265 $accordions.each(addSpacer); 266 $accordions.on("click", "h4", toggleAccordion); 267 268 //Dinning & Social page 269 $accordionsDinning.each(showFirst); 270 $accordionsDinning.on("click", "h4", toggleAccordionDinning); 271 272 function addSpacer() { 273 var $this = $(this); 274 if ($this.is(":first-child")) { 275 $this.addClass("active").find(".table").show(); 276 } 277 $('<div class="spacer"></div>').insertAfter($this.find("h4")); 278 } 279 280 function showFirst() { 281 var $this = $(this); 282 if ($this.is(":first-child")) { 283 $this.addClass("active").find(".items").show(); 284 } 285 } 286 287 function toggleAccordion() { 288 var $header = $(this), 289 $parent = $header.parent(), 290 $content = $parent.find(".table"); 291 292 if ($parent.hasClass("active")) { 293 $content.slideUp(); 294 $parent.removeClass("active"); 295 } 296 else { 297 $content.slideDown(); 298 $parent.addClass("active"); 299 } 300 } 301 302 303 function toggleAccordionDinning() { 304 var $header = $(this), 305 $parent = $header.parent(),
306 $content = $parent.find(".items"); 307 308 if ($parent.hasClass("active")) { 309 $content.slideUp(); 310 $parent.removeClass("active"); 311 } 312 else { 313 $content.slideDown(); 314 $parent.addClass("active"); 315 } 316 } 317 318 }, 319 //--------------------------------- 320 //-- SITE 321 //--------------------------------- 322 navTrigger: function() { 323 /*$navBtn.on("click", toggleMenu); 324 $nav.find(".close-btn").on("click", closeMenu); 325 $win.resize(closeMenu); 326 events.on("scroll_to_link_click", closeMenu);*/ 327 328 function toggleMenu() { 329 $navBtn.toggleClass("active"); 330 $nav.toggleClass("open", $navBtn.hasClass("active")); 331 $body.toggleClass("nav-open", $navBtn.hasClass("active")); 332 $.scrollLock($navBtn.hasClass("active")); 333 } 334 function closeMenu() { 335 $navBtn.removeClass("active"); 336 $nav.removeClass("open"); 337 $body.removeClass("nav-open"); 338 $.scrollLock(false); 339 } 340 }, 341 scrollToLinks: function() { 342 var $scrollToLinks = $('a[href^="#"], a[href^="/#"]').not(".no-scrollto"); 343 344 $scrollToLinks.on("click", function(e) { 345 var href = $(this).attr("href").replace("/", ""), 346 $section = (href === "#") ? $() : $(href);//jQuery 3 without Migrate throws on $("#"); Migrate used to return an empty set here 347 348 if (href == "#" || $section.length) { e.preventDefault(); } 349 if ($section.length) { 350 events.emit("scroll_to_link_click"); 351 $html.add($body).animate({ 352 scrollTop: $section.offset().top 353 }, 1000); 354 //Accessibility 355 if ($section.is("a, select, input, textarea, button")) { $section.focus(); } 356 } 357 else if (href.includes("#")) { 358 cl("no match", href); 359 } 360 }); 361 },//scrollToLinks() 362 fadeOnScroll: function() { 363 var $elements = $(".onscroll.fadein"); 364 if (!$elements.length) { return; } 365 366 $elements.each(function() { 367 var $this = $(this), 368 trigger = ( $this.attr("data-onscroll-trigger") ) ? $this.attr("data-onscroll-trigger") : $this[0], 369 triggerStart = ( $this.attr("data-onscroll-triggerstart") ) ? $this.attr("data-onscroll-triggerstart") : "top center", 370 duration = ( $this.attr("data-onscroll-duration") ) ? pI( $this.attr("data-onscroll-duration") ) : 1; 371 gsap.set($this, { autoAlpha: 0 }); 372 gsap.to($this, { 373 scrollTrigger: { trigger: trigger, start: triggerStart }, 374 autoAlpha: 1, 375 duration: duration, 376 onComplete: clearProps, 377 onCompleteParams: [$this] 378 }); 379 380 function clearProps($target) { 381 gsap.set($target, { clearProps: "opacity,visibility" }); 382 } 383 }); 384 }, 385 modalTrigger: function() { 386 var $modal = $(".modal"); 387 388 $modal.appendTo($body); 389 $doc.on("click", ".js-modal-trigger", openModal); 390 $doc.on("click", ".modal .close-btn", closeModal); 391 $win.on("resize", closeModal); 392 393 function openModal() { 394 var $target = $(`.modal${$(this).attr("data-target")}`); 395 if (!$target.length) { cl(`no modal target: ${$(this).attr("data-target")}`); return; } 396 397 $target.addClass("open"); 398 $body.addClass("modal-open"); 399 $.scrollLock(true); 400 } 401 function closeModal() { 402 $(".modal").removeClass("open"); 403 $body.removeClass("modal-open"); 404 $.scrollLock(false); 405 } 406 }, 407 //--------------------------------- 408 //-- GLOBAL 409 //--------------------------------- 410 window: function() { 411 //-- Scroll 412 var ticking = false;
413 $win.on("scroll", handleScrolling); 414 function handleScrolling(e) { 415 if (!ticking) { 416 window.requestAnimationFrame(function() { 417 updateScrollPos(); 418 ticking = false; 419 }); 420 ticking = true; 421 } 422 } 423 function updateScrollPos() { 424 var scrollTop = $win.scrollTop(); 425 if (scrollY == scrollTop) { return; }//only update if scroll position has changed 426 scrollY = scrollTop; 427 events.emit("scrollYChanged"); 428 } 429 430 //-- Resize 431 $win.on("resize", checkVariables); 432 function checkVariables() { 433 if (winWidth != $win.width()) { 434 updateWidth(); 435 } 436 if (winHeight != $win.height()) { 437 updateHeight(); 438 } 439 } 440 function updateWidth() { 441 winWidth = $win.width(); 442 events.emit("winWidthChange"); 443 } 444 function updateHeight() { 445 winHeight = $win.height(); 446 events.emit("winHeightChanged"); 447 } 448 },//window() 449 document: function() { 450 //-- Document Height 451 $win.on("resize", updateDocHeight); 452 events.on("elHeightChange", updateDocHeight); 453 function updateDocHeight() { 454 var newDocHeight = $doc.height(); 455 if (newDocHeight != docHeight) { 456 docHeight = newDocHeight; 457 events.emit("docHeightChanged", docHeight); 458 } 459 } 460 },//document() 461 body: function() { 462 var atTopVal = 0, 463 lastScrollY = scrollY; 464 465 setup(); 466 events.on("scrollYChanged", updateScrollClasses); 467 468 function setup() { 469 //== Initial setup 470 (scrollY <= atTopVal) ? $body.addClass("at-top") : $body.removeClass("at-top"); 471 ((scrollY + winHeight) == docHeight) ? $body.addClass("at-bottom") : $body.removeClass("at-bottom"); 472 $body.addClass("ready"); 473 } 474 function updateScrollClasses() { 475 //If scrolling up or down 476 (lastScrollY > scrollY) ? $body.removeClass("scrolling-down").addClass("scrolling-up") : $body.addClass("scrolling-down").removeClass("scrolling-up"); 477 //If at top of page 478 (scrollY <= atTopVal) ? $body.removeClass("scrolling-down").removeClass("scrolling-up").addClass("at-top") : $body.removeClass("at-top"); 479 //If at bottom of page 480 ((scrollY + winHeight + 1) >= docHeight) ? $body.addClass("at-bottom") : $body.removeClass("at-bottom");//console.log("scrollTop + windowHeight:", (scrollTop + winHeight + 1)) 481 //Update lastScrollY var 482 lastScrollY = scrollY; 483 } 484 },//body() 485 }; 486 487 488 //----------------------------------------------------------------------- 489 //-- HELPER FUNCTIONS 490 //----------------------------------------------------------------------- 491 //-- Events Object Setup --// 492 function eventsObj() { 493 return { 494 events: {}, 495 on: function(eventName, fn) { 496 this.events[eventName] = this.events[eventName] || []; 497 this.events[eventName].push(fn); 498 }, 499 off: function(eventName, fn) { 500 if (this.events[eventName]) { 501 for (var i = 0; i < this.events[eventName].length; i++) { 502 if (this.events[eventName][i] === fn) { 503 this.events[eventName].splice(i, 1); 504 break; 505 } 506 }; 507 } 508 }, 509 emit: function(eventName, data) { 510 if (this.events[eventName]) { 511 this.events[eventName].forEach(function(fn) { 512 fn(data); 513 }); 514 } 515 } 516 }; 517 } 518 //-- Console Log Shortcut --// 519 function cl() { 520 /* no-op: debug console.log() shortcut disabled for production (was console.log passthrough) */ 521 } 522 //-- Media Matches Shortcut --// 523 function mq(mediaQuery) { 524 switch (mediaQuery) { 525 case "phone": mediaQuery = "(max-width: 767px), screen and (max-width: 812px) and (orientation: landscape)"; break; 526 case "not phone": mediaQuery = "(min-width: 768px)"; break; 527 case "tablet": mediaQuery = "(max-width: 1023px)"; break; 528 case "desktop": mediaQuery = "(min-width: 1024px)"; break; 529 case "portrait": mediaQuery = "(orientation: portrait)"; break; 530 case "landscape": mediaQuery = "(orientation: landscape)"; break; 531 default: mediaQuery = mediaQuery; 532 } 533 mediaQuery = (!mediaQuery.includes("(") && !mediaQuery.includes(")")) ? `(${mediaQuery})` : mediaQuery;//if forget to put () 534 return window.matchMedia(mediaQuery).matches; 535 } 536 //-- Detect Mobile Devices --// 537 function mobileDevice(device) { 538 var deviceCheck; 539 switch(device) { 540 case 'android':
541 deviceCheck = /Android/i.test(navigator.userAgent); 542 break; 543 case 'iOS': 544 deviceCheck = /iPhone|iPad|iPod/i.test(navigator.userAgent); 545 break; 546 default: 547 deviceCheck = /Android|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent); 548 }; 549 return deviceCheck; 550 } 551 //-- Parse Int Shortcut --// 552 function pI(int) { 553 return parseInt(int); 554 } 555 //-- Parse Float Shortcut --// 556 function pF(int) { 557 return parseFloat(int); 558 } 559 //-- GetBoundingClientRect Shortcut --// 560 function getBound(el) {//takes dom obj or jquery obj 561 var node = (typeof el === "string") ? document.querySelector(el) : (el instanceof jQuery) ? el[0] : el; 562 return node.getBoundingClientRect(); 563 } 564 //-- JSON String --// 565 function isJson(str) { 566 try { JSON.parse(str); } 567 catch(err) { return false; } 568 return true; 569 } 570 //-- jQuery Shuffle Method (need to call before use) --// 571 function $shuffle() { 572 //-- Shuffle an array of jQuery elements --// 573 $.fn.shuffle = function() { 574 var allElems = this.get(), 575 getRandom = function(max) { 576 return Math.floor(Math.random() * max); 577 }, 578 shuffled = $.map(allElems, function(){ 579 var random = getRandom(allElems.length), 580 randEl = $(allElems[random]).clone(true)[0]; 581 allElems.splice(random, 1); 582 return randEl; 583 }); 584 585 this.each(function(i){ 586 $(this).replaceWith($(shuffled[i])); 587 }); 588 589 return $(shuffled); 590 }; 591 } 592 //-- Check if el in viewport --// 593 function isInViewport(el) { 594 var bounding = el.getBoundingClientRect(),//console.log("el",el);console.log("bounding",bounding); 595 isVisible = ( 596 //Y Axis 597 ( 598 (bounding.top >= 0 && bounding.top <= winHeight) 599 || 600 (bounding.bottom >= 0 && bounding.bottom <= winHeight) 601 ) 602 );//console.log("isVisible",isVisible); 603 return isVisible; 604 } 605 //-- Get scroll position as percentage (how far scrolled down page) --// 606 function getScrolledPercent(round = false) { 607 var scrollableLength = docHeight - winHeight, 608 scrollFraction = scrollableLength / 100, 609 scrolledAmount = scrollY / scrollFraction;//cl(`scrolled percent: ${scrolledAmount}`); 610 return (round) ? Math.round(scrolledAmount) : scrolledAmount; 611 } 612 //-- Get Scroll Element Trigger Point --// 613 function getScrollTriggerPoint($el, triggerOffset = 0, triggerHook = "onEnter") { 614 var offset = $el.offset(), 615 screenOffset = getScreenOffset(), 616 scrollTriggerPoint = offset.top; 617 618 //Screen Offset 619 scrollTriggerPoint-=screenOffset; 620 //Trigger Offset 621 scrollTriggerPoint = (typeof triggerOffset === "number") ? scrollTriggerPoint + triggerOffset : scrollTriggerPoint; 622 623 return (scrollTriggerPoint > 0) ? scrollTriggerPoint : 0; 624 625 function getScreenOffset() { 626 var hookOffset; 627 if (typeof triggerHook === "string") { 628 switch(triggerHook) { 629 case "onCenter": 630 hookOffset = winHeight / 2; 631 break; 632 case "onLeave": 633 hookOffset = 0; 634 break; 635 default://"onEnter" 636 hookOffset = winHeight; 637 } 638 } 639 else { 640 hookOffset = (typeof triggerHook === "number" && triggerHook <= 1 && triggerHook >= 0) ? triggerHook * winHeight : winHeight; 641 } 642 return hookOffset; 643 } 644 } 645 //-- Run Modules --// 646 function runModules() { 647 $.each(modules, function() { this(); }); 648 } 649 650 651 652 //----------------------------------------------------------------------- 653 //-- INIT 654 //----------------------------------------------------------------------- 655 if (window.WUA.assets.isLoaded) { 656 runModules(); 657 } 658 else {
659 window.WUA.events.on("wua_assets_loaded", runModules); 660 } 661 //events.emit("siteReady");cl("siteReady"); 662 663 664}); // document ready
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.