1(function () { 2 'use strict'; 3 4 function prefersReducedMotion() { 5 return window.matchMedia('(prefers-reduced-motion: reduce)').matches; 6 } 7 8 function onReady(fn) { 9 if (document.readyState === 'loading') { 10 document.addEventListener('DOMContentLoaded', fn); 11 } else { 12 fn(); 13 } 14 } 15 16 function initOutcomesCarousel() { 17 var carousel = document.getElementById('outcomesCarousel'); 18 if (!carousel) { 19 return; 20 } 21 22 var track = carousel.querySelector('.outcomes__track'); 23 var slides = carousel.querySelectorAll('.outcomes__slide'); 24 var section = carousel.closest('.outcomes'); 25 var indicators = section ? section.querySelectorAll('.outcomes__indicator') : []; 26 var progressBar = carousel.querySelector('.outcomes__progress-bar'); 27 var totalSlides = slides.length; 28 var currentSlide = 0; 29 30 function updateCarousel() { 31 track.style.transition = prefersReducedMotion() ? 'none' : ''; 32 track.style.transform = 'translateX(' + (-currentSlide * 100) + '%)'; 33 34 slides.forEach(function (slide, index) { 35 slide.classList.toggle('outcomes__slide--active', index === currentSlide); 36 }); 37 38 indicators.forEach(function (indicator, index) { 39 indicator.classList.toggle('outcomes__indicator--active', index === currentSlide); 40 }); 41 42 if (progressBar) { 43 progressBar.style.transform = 'translateX(' + (currentSlide * 100) + '%)'; 44 } 45 } 46 47 function goToSlide(index) { 48 if (index < 0 || index >= totalSlides) { 49 return; 50 } 51 currentSlide = index; 52 updateCarousel(); 53 } 54 55 function setIframePointerEvents(enable) { 56 carousel.querySelectorAll('iframe').forEach(function (frame) { 57 frame.style.pointerEvents = enable ? 'auto' : 'none'; 58 }); 59 } 60 61 if (prefersReducedMotion()) { 62 carousel.style.cursor = 'default'; 63 } 64 65 indicators.forEach(function (indicator, index) { 66 indicator.addEventListener('click', function () { 67 goToSlide(index); 68 }); 69 }); 70 71 var isDown = false; 72 var startPos = 0; 73 var currentPos = 0; 74 var rafId = null; 75 var touchStartX = 0; 76 var touchCurrentX = 0; 77 78 carousel.addEventListener('mousedown', function (e) { 79 isDown = true; 80 startPos = e.clientX; 81 carousel.style.cursor = 'grabbing'; 82 setIframePointerEvents(false); 83 }); 84 85 carousel.addEventListener('mousemove', function (e) { 86 if (!isDown) { 87 return; 88 } 89 e.preventDefault(); 90 currentPos = e.clientX; 91 if (rafId) { 92 cancelAnimationFrame(rafId); 93 } 94 rafId = requestAnimationFrame(function () { 95 var diff = currentPos - startPos; 96 var translateX = -currentSlide * 100 + (diff / carousel.offsetWidth) * 100; 97 track.style.transform = 'translateX(' + translateX + '%)'; 98 track.style.transition = 'none'; 99 }); 100 }, { passive: false }); 101 102 function releaseDrag(diff) { 103 isDown = false; 104 carousel.style.cursor = 'grab'; 105 track.style.transition = ''; 106 setIframePointerEvents(true); 107 var threshold = carousel.offsetWidth * 0.2; 108 if (Math.abs(diff) > threshold) { 109 if (diff > 0 && currentSlide > 0) { 110 goToSlide(currentSlide - 1); 111 } else if (diff < 0 && currentSlide < totalSlides - 1) { 112 goToSlide(currentSlide + 1); 113 } else { 114 updateCarousel(); 115 } 116 } else { 117 updateCarousel(); 118 } 119 } 120 121 carousel.addEventListener('mouseup', function () { 122 if (!isDown) { 123 return; 124 } 125 releaseDrag(currentPos - startPos); 126 }); 127 128 carousel.addEventListener('mouseleave', function () { 129 if (!isDown) { 130 return; 131 } 132 releaseDrag(currentPos - startPos); 133 }); 134 135 carousel.addEventListener('touchstart', function (e) { 136 touchStartX = e.touches[0].clientX; 137 setIframePointerEvents(false); 138 }, { passive: true }); 139 140 carousel.addEventListener('touchmove', function (e) { 141 touchCurrentX = e.touches[0].clientX; 142 var diff = touchCurrentX - touchStartX; 143 var translateX = -currentSlide * 100 + (diff / carousel.offsetWidth) * 100; 144 track.style.transform = 'translateX(' + translateX + '%)'; 145 track.style.transition = 'none'; 146 }, { passive: true }); 147 148 carousel.addEventListener('touchend', function () { 149 track.style.transition = ''; 150 releaseDrag(touchCurrentX - touchStartX); 151 }, { passive: true }); 152 153 updateCarousel(); 154 } 155 156 function initRoomsLightbox() { 157 var section = document.querySelector('.rooms-available'); 158 var lightbox = document.getElementById('rooms-lightbox'); 159 if (!section || !lightbox) { 160 return; 161 } 162 163 var lightboxImage = document.getElementById('lightbox-image'); 164 var lightboxOverlay = lightbox.querySelector('.rooms-available__lightbox-overlay'); 165 var lightboxClose = lightbox.querySelector('.rooms-available__lightbox-close'); 166 if (lightbox.parentNode !== document.body) { 167 document.body.appendChild(lightbox); 168 } 169 170 var roomTriggers = section.querySelectorAll('.rooms-available__room-title--clickable'); 171 var roomImages = {}; 172 173 try { 174 roomImages = JSON.parse(section.getAttribute('data-room-images') || '{}'); 175 } catch (e) { 176 roomImages = {}; 177 } 178 179 function openLightbox(roomType) { 180 if (!lightboxImage || !roomImages[roomType]) { 181 return; 182 } 183 lightboxImage.src = roomImages[roomType]; 184 var roomName = 185 roomType === 'signature' 186 ? 'Signature Suite' 187 : roomType.charAt(0).toUpperCase() + roomType.slice(1) + ' Room'; 188 lightboxImage.alt = roomName; 189 lightbox.removeAttribute('hidden'); 190 document.body.style.overflow = 'hidden'; 191 } 192 193 function closeLightbox() { 194 lightbox.setAttribute('hidden', ''); 195 document.body.style.overflow = ''; 196 } 197
198 roomTriggers.forEach(function (trigger) { 199 trigger.addEventListener('click', function (e) { 200 e.preventDefault(); 201 var roomType = trigger.getAttribute('data-room'); 202 if (roomType) { 203 openLightbox(roomType); 204 } 205 }); 206 }); 207 208 if (lightboxOverlay) { 209 lightboxOverlay.addEventListener('click', closeLightbox); 210 } 211 if (lightboxClose) { 212 lightboxClose.addEventListener('click', closeLightbox); 213 } 214 215 document.addEventListener('keydown', function (e) { 216 if (e.key === 'Escape' && !lightbox.hasAttribute('hidden')) { 217 closeLightbox(); 218 } 219 }); 220 } 221 222 onReady(function () { 223 initOutcomesCarousel(); 224 initRoomsLightbox(); 225 }); 226})();
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.