1// Layout 2window.layout = { 3 4 // Load 5 load: function (url, data, callback) { 6 7 // Variables 8 var response = null, 9 ready = null, 10 complete = function () { 11 if (ready && response) { 12 $('html').removeClass('ToggleLoading'); 13 if (callback) { 14 callback(response); 15 } 16 } 17 }; 18 19 // Class 20 $('html').addClass('ToggleLoading'); 21 22 // Ajax 23 $.ajax({ 24 type: 'POST', 25 url: url, 26 data: data, 27 cache: false, 28 contentType: false, 29 processData: false, 30 timeout: 20000, 31 success: function (data) { 32 response = data; 33 complete(); 34 }, 35 error: function () { 36 $('html').addClass('ToggleError'); 37 } 38 }); 39 40 // Timeout 41 setTimeout(function () { 42 ready = true; 43 complete(); 44 }, 500); 45 46 }, 47 48 // Modals 49 modals: function () { 50 51 // Variables 52 var $modal = $('.Modal'), 53 $foreground = $modal.find('.Foreground'); 54 55 // Close 56 $modal.on('click', '.Close, .Background', function (event) { 57 event.preventDefault(); 58 $modal.hide(); 59 $foreground.empty(); 60 }); 61 62 // Open 63 $(document).on('click', '.TriggerModal', function (event) { 64 65 if ($('html').hasClass('App')) return; 66 67 // Variables 68 var breakpoint = $(this).attr('data-disable-below') ? layout.widths[$(this).attr('data-disable-below').toLowerCase()] : 0, 69 callback = $(this).attr('data-callback'); 70 71 // Check 72 if ($(window).width() > breakpoint) { 73 74 // Stop 75 event.preventDefault(); 76 77 // Load 78 layout.load($(this).attr('data-href'), null, function (data) { 79 $foreground.html(data); 80 $modal.show(); 81 if (callback) { 82 window.layout[callback](); 83 } 84 }); 85 86 } 87 88 }); 89 90 }, 91 92 // Toggles 93 toggles: function () { 94 95 // Toggle 96 $(document).on('click', '.Toggle', function (event) { 97 98 // Variables 99 var $parent = $(this).attr('data-parent') ? $(this).parents($(this).attr('data-parent')) : $(this).parent(), 100 name = $(this).attr('data-class') ? 'Toggle' + $(this).attr('data-class') : 'Toggled', 101 callback = $(this).attr('data-callback'); 102 103 // Stop 104 event.preventDefault(); 105 106 // Toggle 107 $(this).toggleClass('Toggled'); 108 $parent.toggleClass(name); 109 if (callback) { 110 window.layout[callback](); 111 } 112 113 }); 114 115 }, 116 117 // Search 118 search: function () { 119 120 // Variables 121 var loading = null, 122 timeout = null, 123 keyword = null, 124 $form = $('.Header > .Search'), 125 $input = $form.find('input'), 126 startTimeout = function () { 127 timeout = setTimeout(function () { 128 request(); 129 timeout = null; 130 }, 500); 131 }, 132 stopTimeout = function () { 133 clearTimeout(timeout); 134 timeout = null; 135 }, 136 request = function () { 137 if (!loading && keyword !== $.trim($input.val())) { 138 loading = true; 139 keyword = $.trim($input.val()); 140 $.ajax({ 141 type: 'POST', 142 url: $form.attr('data-action'), 143 data: { 'keyword': keyword }, 144 success: function (data) { 145 $form.find('.Wrapper').replaceWith($(data).filter('.Wrapper')); 146 if (timeout === null && keyword !== $.trim($input.val())) { 147 startTimeout(); 148 } 149 loading = false; 150 } 151 }); 152 } 153 }; 154 155 // Submit 156 $form.on('submit', function (event) { 157 event.preventDefault(); 158 }); 159 160 // Key Up 161 $input.on('keyup', function (event) { 162 stopTimeout(); 163 if (event.which === 13 || event.which === 32) { 164 request(); 165 } else { 166 startTimeout(); 167 } 168 }); 169 170 }, 171 172 // Sub Menu 173 subMenu: function () { 174 175 // Variables 176 var $subMenu = $('.Header .SubMenu'), swiper; 177 178 // Swiper 179 if ($subMenu.length) { 180 swiper = new Swiper($('.Header .SubMenu .swiper-container'), { 181 slidesPerView: 'auto', 182 watchOverflow: true, 183 freeMode: true 184 }); 185 } 186 187 }, 188 189 loggedInStatus: function () { 190 const signOutLink = document.getElementById("signOutLink"); 191 const memberKey = "movingstory.member"; 192 193 if (signOutLink) { 194 signOutLink.addEventListener("click", function (event) { 195 event.preventDefault(); // Prevent immediate navigation 196 sessionStorage.removeItem(memberKey); // Remove sessionStorage key 197 198 // After removing, navigate to the logout page 199 window.location.href = "/logout"; 200 }); 201 } 202 203 function isLoggedIn() { 204 const memberData = sessionStorage.getItem(memberKey); 205 return memberData && memberData !== "{}"; 206 } 207 async function fetchMemberData() { 208 try { 209 const response = await fetch("/api/member"); 210 const data = await response.json(); 211 sessionStorage.setItem(memberKey, JSON.stringify(data)); 212 return data; 213 } catch (error) { 214 console.error("Error fetching member data:", error); 215 } 216 } 217 function toggleHeader() { 218 if (isLoggedIn()) { 219 document.querySelector('.Header .Buttons')?.classList.add('authenticated');
220 const signInElement = document.querySelector('.Drawer .SignIn'); 221 if (signInElement) { 222 signInElement.textContent = 'My Account'; 223 } 224 } else { 225 document.querySelector('.Header .Buttons')?.classList.remove('authenticated'); 226 const signInElement = document.querySelector('.Drawer .SignIn'); 227 if (signInElement) { 228 signInElement.textContent = 'Club Sign In'; 229 } 230 } 231 } 232 async function init() { 233 let memberData = sessionStorage.getItem(memberKey); 234 if (!memberData) { 235 await fetchMemberData(); 236 } 237 toggleHeader(); 238 } 239 init(); 240 }, 241 242 // Homepage Featured Video 243 features: function () { 244 245 // Variables 246 var $features = $('.Features'), 247 $videos = $features.find('video'), 248 swiper, 249 activeIndex = 0; 250 251 // Function to load video by index 252 var loadVideo = function (index) { 253 254 // Variables 255 var $this = $videos.eq(index), 256 request = new XMLHttpRequest(); 257 258 // Check if the video element exists and isn't already loaded 259 if ($this.length && !$this.hasClass('Loaded')) { 260 261 // Load the video 262 request.onload = function () { 263 if (this.status === 200) { 264 $this.attr('src', URL.createObjectURL(this.response)); 265 setTimeout(function () { 266 $this.addClass('Loaded'); // Mark as loaded 267 if (index === activeIndex) { // Play only the current active video 268 $this.get(0).play(); 269 } 270 }, 2000); 271 } 272 }; 273 274 request.open('GET', $this.attr('data-src'), true); 275 request.responseType = 'blob'; 276 request.send(); 277 } 278 }; 279 280 if ($features.length) { 281 chook.lazyloader($features, function () { 282 // Initialize Swiper 283 swiper = new Swiper($features.find('.swiper-container'), { 284 navigation: { 285 nextEl: $features.find('.swiper-button-next'), 286 prevEl: $features.find('.swiper-button-prev'), 287 }, 288 pagination: { 289 el: $features.find('.swiper-pagination'), 290 clickable: true 291 }, 292 on: { 293 slideChange: function () { 294 // Pause the currently active video when the slide changes 295 $features.find('.swiper-slide-active video').get(0).pause(); 296 }, 297 slideChangeTransitionEnd: function () { 298 // Update activeIndex 299 activeIndex = swiper.activeIndex; 300 301 // Load and play the current active slide's video 302 $features.find('.swiper-slide-active video').get(0).play(); 303 304 // Load the current slide's video and preload the next slide's video 305 loadVideo(activeIndex); 306 loadVideo(activeIndex + 1); 307 } 308 }, 309 autoplay: { 310 delay: 20000, 311 }, 312 speed: 500, 313 watchOverflow: true, 314 roundLengths: true 315 }); 316 317 }, function () { 318 loadVideo(0); 319 window.setTimeout(function () { 320 loadVideo(1); 321 }, 4000); 322 }); 323 } 324 325 }, 326 327 // Swipers 328 swipers: function () { 329 330 function sizeFilters($filters, slides) { 331 332 $filters.removeClass('scrollable').css('width', ''); 333 334 var available = $filters.parent().width(); 335 336 //get total width of all slides 337 var totalWidth = 100; 338 slides.each(function () { 339 totalWidth += $(this).outerWidth(); 340 }); 341 342 if (totalWidth < 1440) { 343 $filters.width(Math.min(totalWidth, available)); 344 } else { 345 $filters.addClass('scrollable'); 346 } 347 } 348 349 function filterSlides($swiper) { 350 return $swiper.children('.swiper-container').children('.swiper-wrapper').children('.swiper-slide'); 351 } 352 353 function intialiseSwiper() { 354 $('.Filters > .swiper').each(function () { 355 356 // Variables 357 var $swiper = $(this), 358 breakpoints = {}, 359 swiper; 360
361 // Breakpoint 362 breakpoints[layout.widths.tablet + layout.widths.scrollbar] = { 363 slidesPerGroup: 2 364 }; 365 366 sizeFilters($swiper.closest('.Filters'), filterSlides($swiper)); 367 368 // Swiper 369 swiper = new Swiper($swiper.children('.swiper-container'), { 370 pagination: { 371 el: $swiper.children('.swiper-pagination'), 372 clickable: true 373 }, 374 slidesPerView: 'auto', 375 slidesPerGroup: 3, 376 watchOverflow: true, 377 roundLengths: true, 378 freeMode: true, 379 navigation: { 380 nextEl: $swiper.children('.swiper-button-next'), 381 prevEl: $swiper.children('.swiper-button-prev'), 382 }, 383 breakpoints: breakpoints 384 }); 385 386 }); 387 } 388 389 function debounce(func, wait) { 390 let timeout; 391 return function () { 392 const context = this, args = arguments; 393 clearTimeout(timeout); 394 timeout = setTimeout(() => func.apply(context, args), wait); 395 }; 396 } 397 398 intialiseSwiper(); 399 400 $(window).resize(debounce(function () { 401 $('.Filters > .swiper').each(function () { 402 var $swiper = $(this), 403 container = $swiper.children('.swiper-container')[0], 404 swiper = container && container.swiper; 405 406 sizeFilters($swiper.closest('.Filters'), filterSlides($swiper)); 407 408 if (swiper && !swiper.destroyed) { 409 swiper.update(); 410 swiper.navigation.update(); 411 } 412 }); 413 }, 250)); 414 415 // Loop 416 $('.Widget > .Boundary > .swiper').each(function () { 417 418 // Variables 419 var breakpoints = {}, 420 swiper; 421 422 // Breakpoint 423 breakpoints[layout.widths.tablet + layout.widths.scrollbar] = { 424 slidesPerGroup: 2 425 }; 426 427 // Swiper 428 swiper = new Swiper($(this).children('.swiper-container'), { 429 pagination: { 430 el: $(this).children('.swiper-pagination'), 431 clickable: true 432 }, 433 slidesPerView: 'auto', 434 slidesPerGroup: 3, 435 watchOverflow: true, 436 roundLengths: true, 437 freeMode: true, 438 breakpoints: breakpoints 439 }); 440 441 }); 442 443 }, 444 445 // Feeds 446 feeds: function () { 447 448 // Load 449 WebFont.load({ 450 custom: { 451 families: [layout.fonts.bold, layout.fonts.regular] 452 }, 453 classes: false 454 }); 455 456 }, 457 458 // https://stackoverflow.com/questions/27078285/simple-throttle-in-js/27078401 459 // Returns a function, that, when invoked, will only be triggered at most once 460 // during a given window of time. Normally, the throttled function will run 461 // as much as it can, without ever going more than once per `wait` duration; 462 // but if you'd like to disable the execution on the leading edge, pass 463 // `{leading: false}`. To disable execution on the trailing edge, ditto. 464 throttle: function (func, wait, options) { 465 var context, args, result; 466 var timeout = null; 467 var previous = 0; 468 if (!options) options = {}; 469 var later = function () { 470 previous = options.leading === false ? 0 : Date.now(); 471 timeout = null; 472 result = func.apply(context, args); 473 if (!timeout) context = args = null; 474 }; 475 return function () { 476 var now = Date.now(); 477 if (!previous && options.leading === false) previous = now; 478 var remaining = wait - (now - previous); 479 context = this; 480 args = arguments; 481 if (remaining <= 0 || remaining > wait) { 482 if (timeout) { 483 clearTimeout(timeout); 484 timeout = null; 485 } 486 previous = now; 487 result = func.apply(context, args); 488 if (!timeout) context = args = null; 489 } else if (!timeout && options.trailing !== false) { 490 timeout = setTimeout(later, remaining); 491 } 492 return result; 493 }; 494 }, 495 496 // Tickets 497 tickets: function () { 498 499 // Tickets 500 $('.Tickets').each(function () { 501 502 // Variables 503 var $this = $(this), 504 $days = $this.find('.swiper a'), 505 $sessions = $this.find('.Sessions'), 506 swiper; 507 508 // Days 509 $days.click(function (event) { 510 event.preventDefault(); 511 $sessions.addClass('Hidden').eq($days.index($(this))).removeClass('Hidden'); 512 $days.removeClass('Selected'); 513 $(this).addClass('Selected'); 514 }); 515 516 // Swiper 517 swiper = new Swiper($this.find('.swiper-container'), { 518 navigation: { 519 nextEl: $this.find('.swiper-button-next'), 520 prevEl: $this.find('.swiper-button-prev'), 521 }, 522 slidesPerView: 'auto', 523 watchOverflow: true, 524 freeMode: true 525 }); 526 527 // Resize 528 $(window).resize(function () { 529 try {
530 swiper.update(); 531 } 532 catch (e) { 533 } 534 }); 535 536 }); 537 538 }, 539 540 // Filters 541 filters: function () { 542 543 // Variables 544 var $filters = $('.Filters'), 545 $links = $filters.find('a'), 546 swiper; 547 548 // Links 549 $links.click(function (event) { 550 event.preventDefault(); 551 $links.removeClass('Selected'); 552 $(this).addClass('Selected'); 553 $.ajax({ 554 type: 'GET', 555 url: $(this).attr('href'), 556 success: function (data) { 557 $('.Movies').replaceWith($(data).find('.Movies')); 558 559 // if in app via iframe trigger resize 560 if (window.top !== window.self) { 561 if (app && app.watchImages) app.watchImages(); 562 $(window).trigger('resize'); 563 } 564 } 565 }); 566 }); 567 }, 568 569 // Gallery 570 gallery: function () { 571 572 // Variables 573 var swiper; 574 575 // Swiper 576 swiper = new Swiper($('.Gallery .swiper-container'), { 577 slidesPerView: 'auto', 578 watchOverflow: true, 579 freeMode: true 580 }); 581 582 }, 583 584 // Media 585 media: function () { 586 587 // Variables 588 var $media = $('.Modal .Media'), 589 $trigger = $('.TriggerModal[data-id="' + $media.attr('data-id') + '"]'), 590 $triggers = $trigger.parents('.Gallery').find('.TriggerModal'); 591 592 // Check 593 if ($triggers.length) { 594 $media.find('.Arrow').removeClass('Hidden'); 595 } 596 597 // Click 598 $media.find('.Arrow').click(function (event) { 599 var index = $triggers.index($trigger); 600 event.preventDefault(); 601 if ($(this).hasClass('Previous')) { 602 index = index - 1 >= 0 ? index - 1 : $triggers.length - 1; 603 } else { 604 index = index + 1 < $triggers.length ? index + 1 : 0; 605 } 606 $media.find('.Close').click(); 607 $triggers.eq(index).click(); 608 }); 609 610 }, 611 612 shop: function () { 613 // Show Cart 614 $('.Header .Shop .Trigger').click(function (event) { 615 event.preventDefault(); 616 }); 617 }, 618 619 // Master 620 master: function () { 621 622 // Modals 623 layout.modals(); 624 625 // Toggles 626 layout.toggles(); 627 628 // Header logged in status 629 layout.loggedInStatus(); 630 631 // Search 632 layout.search(); 633 634 // Sub Menu 635 layout.subMenu(); 636 637 } 638 639};
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.