1document.addEventListener('DOMContentLoaded', function() { 2 const slides = document.querySelectorAll('.slide'); 3 const slider = document.querySelector('.slider'); 4 const sliderContainer = document.querySelector('.slider-container'); 5 const pagination = document.querySelector('.pagination'); 6 const leftArrow = document.querySelector('.arrow.left'); 7 const rightArrow = document.querySelector('.arrow.right'); 8 let currentIndex = 0; 9 let inView = true; // Whether the slider is currently scrolled into view 10 11 if (!slides.length || !slider || !pagination || !leftArrow || !rightArrow) { 12 console.error('Some elements are missing in the DOM.'); 13 return; 14 } 15 16 // Create pagination dots 17 slides.forEach((slide, index) => { 18 const dot = document.createElement('div'); 19 dot.classList.add('dot'); 20 dot.addEventListener('click', () => goToSlide(index)); 21 pagination.appendChild(dot); 22 }); 23 24 const dots = document.querySelectorAll('.dot'); 25 26 // <mux-video> may not be upgraded yet when this classic script runs (the 27 // element definition loads as a deferred module), so guard media calls and 28 // wait for the definition before attempting playback. 29 function safePlay(video) { 30 if (typeof video.play !== 'function') { 31 if (window.customElements) { 32 customElements.whenDefined('mux-video').then(() => safePlay(video)); 33 } 34 return; 35 } 36 const played = video.play(); 37 if (played && played.catch) played.catch(() => {}); 38 } 39 40 function safePause(video) { 41 if (typeof video.pause === 'function') video.pause(); 42 } 43 44 // Play the Mux background video for a given slide (created lazily, reused after). 45 function playVideo(index) { 46 const slide = slides[index]; 47 const muxId = slide.getAttribute('data-mux-id'); 48 if (!muxId) return; 49 50 let video = slide.querySelector('mux-video'); 51 if (!video) { 52 video = document.createElement('mux-video'); 53 video.setAttribute('playback-id', muxId); 54 video.setAttribute('stream-type', 'on-demand'); 55 video.setAttribute('preload', 'auto'); 56 video.setAttribute('loop', ''); // Loop, since auto-progression is disabled 57 video.setAttribute('muted', ''); 58 video.muted = true; // Required for autoplay 59 video.setAttribute('playsinline', ''); // Prevent fullscreen on iOS 60 // The HLS source loads asynchronously from the playback-id, so calling 61 // play() right away rejects. The autoplay attribute starts playback as 62 // soon as the source is ready; only enable it if the slide is in view. 63 if (inView) video.setAttribute('autoplay', ''); 64 slide.appendChild(video); 65 return; 66 } 67 68 // Reused element: source is already loaded, so restart and play directly. 69 try { video.currentTime = 0; } catch (e) {} 70 if (inView) safePlay(video); 71 } 72 73 function stopVideos() {
74 slides.forEach(slide => { 75 const video = slide.querySelector('mux-video'); 76 if (video) { 77 safePause(video); 78 try { video.currentTime = 0; } catch (e) {} 79 } 80 }); 81 } 82 83 function nextSlide() { 84 currentIndex = (currentIndex + 1) % slides.length; 85 updateSlider(); 86 } 87 88 function prevSlide() { 89 currentIndex = (currentIndex - 1 + slides.length) % slides.length; 90 updateSlider(); 91 } 92 93 function goToSlide(index) { 94 currentIndex = index; 95 updateSlider(); 96 } 97 98 function updateSlider() { 99 stopVideos(); // Stop all videos before updating the slider 100 slider.style.transform = `translateX(-${currentIndex * 100}%)`; 101 dots.forEach((dot, i) => { 102 dot.classList.toggle('active', i === currentIndex); 103 }); 104 playVideo(currentIndex); // Play the video in the active slide 105 } 106 107 leftArrow.addEventListener('click', prevSlide); 108 rightArrow.addEventListener('click', nextSlide); 109 110 // Pause the slideshow/video when it's scrolled out of view, resume when back. 111 if (sliderContainer && 'IntersectionObserver' in window) { 112 const observer = new IntersectionObserver((entries) => { 113 entries.forEach(entry => { 114 inView = entry.isIntersecting; 115 const video = slides[currentIndex].querySelector('mux-video'); 116 if (!video) return; 117 if (inView) { 118 safePlay(video); 119 } else { 120 safePause(video); 121 } 122 }); 123 }, { threshold: 0.35 }); 124 observer.observe(sliderContainer); 125 } 126 127 // Initialize the slider and play the first video 128 updateSlider(); 129}); 130 131 132 133 134/*var cookieDismiss = Cookies.get('cookieDismiss'); 135if(cookieDismiss == 'true'){ 136 $( ".cookie-notice" ).hide(); 137} 138 139function cookieNoticeDismiss(){ 140 Cookies.set('cookieDismiss', true, { expires: 365 }); 141 $( ".cookie-notice" ).hide(); 142}*/ 143 144//window.onload = function () { $(".loader").fadeOut(); } 145 146$('.language-button').on('click', function(event) { 147 event.preventDefault(); 148 $( ".language-selector" ).addClass( "active" ); 149}); 150 151$('.mobile-menu_toggle').on('click', function(event) { 152 event.preventDefault(); 153 $( ".mobile-menu-overlay" ).toggle(); 154 $( ".mobile-menu" ).toggleClass( "mobile-menu--open" ); 155 //$( "body" ).toggleClass( "no-scroll" ); 156 $( ".mobile-menu_toggle" ).toggleClass( "--hidden" ); 157}); 158 159$('.main-menu_toggle').on('click', function(event) { 160 event.preventDefault(); 161 $( ".mobile-menu-overlay" ).toggle(); 162 $( ".mobile-menu" ).toggleClass( "mobile-menu--open" ); 163 //$( "body" ).toggleClass( "no-scroll" ); 164 $( ".mobile-nav__toggle" ).toggleClass( "mobile-nav__toggle--active" ); 165}); 166 167$('.mobile-menu-overlay').on('click', function(event) { 168 event.preventDefault(); 169 $( ".mobile-menu-overlay" ).toggle(); 170 $( ".mobile-menu" ).toggleClass( "mobile-menu--open" ); 171 //$( "body" ).toggleClass( "no-scroll" ); 172 $( ".mobile-nav__toggle" ).toggleClass( "mobile-nav__toggle--active" ); 173 $( ".mobile-menu_toggle" ).removeClass( "--hidden" ); 174}); 175 176$('.mobile-menu__submenu').on('click', function(event) { 177 $(this).toggleClass( "mobile-menu__submenu--open"); 178}); 179 180var lazyLoadInstance = new LazyLoad({ 181 elements_selector: ".lazy" 182 // ... more custom settings? 183}); 184 185const animateCSS = (element, animation, prefix = 'animate__') => 186 // We create a Promise and return it 187 new Promise((resolve, reject) => { 188 const animationName = `${prefix}${animation}`; 189 const node = document.querySelector(element); 190 191 node.classList.add(`${prefix}animated`, animationName); 192 193 // When the animation ends, we clean the classes and resolve the Promise 194 function handleAnimationEnd(event) { 195 event.stopPropagation(); 196 node.classList.remove(`${prefix}animated`, animationName); 197 resolve('Animation ended'); 198 } 199 200 node.addEventListener('animationend', handleAnimationEnd, {once: true}); 201 }); 202 203function showSiteNotice(){ 204 $('#info-popup-overlay').removeClass('hidden'); 205 $('#info-popup-container').removeClass('hidden'); 206} 207function hideSiteNotice(){ 208 animateCSS('#info-popup', 'bounceOut').then((message) => { 209 $('#info-popup-overlay').addClass('hidden'); 210 $('#info-popup-container').addClass('hidden'); 211 }); 212} 213 214$('#info-notice-dismiss').click(function(e){ 215 e.preventDefault(); 216 Cookies.set('notice_dismiss', 'true'); 217 hideSiteNotice(); 218}); 219if(Cookies.get('notice_dismiss') != 'true'){ 220 showSiteNotice(); 221} 222/* 223function showBookingPopup(){ 224 $('#booking-popup-overlay').removeClass('hidden'); 225 $('#booking-popup-container').removeClass('hidden'); 226} 227function hideBookingPopup(){ 228 animateCSS('#booking-popup', 'bounceOut').then((message) => { 229 $('#booking-popup-overlay').addClass('hidden'); 230 $('#booking-popup-container').addClass('hidden'); 231 }); 232} 233$('#booking-popup-dismiss').click(function(e){ 234 e.preventDefault(); 235 hideBookingPopup(); 236}); 237*/ 238$('.marquee').marquee({ 239 //speed in milliseconds of the marquee 240 duration: 7000, 241 //time in milliseconds before the marquee will start animating 242 delayBeforeStart: 0, 243 //'left' or 'right' 244 direction: 'left' 245}); 246/* 247$('.homepage-hero').vide({ 248 mp4: 'https://cdn.knockhatch.com/videos/homepageV2.mp4', 249 poster: '/assets/dragon-castle-1.jpg' 250}); 251*/ 252$('.review-slider').flickity({ 253 // options 254 percentPosition: false, 255 wrapAround: true,
256 prevNextButtons: false, 257 pageDots: false, 258 autoPlay: true 259}); 260 261//var rellax = new Rellax('.rellax'); 262function processCalendar(){ 263 264 var calendarEl = document.getElementById('calendar'); 265 if(!calendarEl){ return; } 266 267 var validRange = {}; 268 if(calendarEl.dataset.rangeStart){ validRange.start = calendarEl.dataset.rangeStart; } 269 if(calendarEl.dataset.rangeEnd){ validRange.end = calendarEl.dataset.rangeEnd; } 270 271 $.getJSON('/calendar-api.json', function(response){ 272 273 var calendar = new FullCalendar.Calendar(calendarEl, { 274 plugins: [ 'dayGrid','interaction' ], 275 validRange: validRange, 276 firstDay: 1, 277 dateClick: function(info) { 278 window.location.href = "https://knockhatch.digitickets.co.uk/tickets"; 279 } 280 }); 281 282 calendar.render(); 283 284 (response.data || []).forEach(function(item){ 285 calendar.addEvent({ 286 start: item.startDate, 287 end: item.endDate, 288 rendering: 'background', 289 classNames: [item.type] 290 }); 291 }); 292 }); 293} 294 295function toggleCollapse(id){ 296 event.preventDefault(); 297 $('#collapse-'+id).toggleClass('collapse-item--open'); 298} 299 300 301const swiper = new Swiper('.swiper', { 302 // Optional parameters 303 direction: 'horizontal', 304 loop: true, 305 autoplay: { 306 delay: 3000, 307 }, 308 });
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.