1/* globals themeBuyTickets, themeUx, Pikaday, moment, filmbotCountriesStates */ 2'use strict'; 3//animation top menu 4;(function ( $ ) { 5 window.themeTopMenu = { 6 init: function () { 7 themeTopMenu.initProps(); 8 themeTopMenu.attachEvents(); 9 }, 10 initProps: function () { 11 themeTopMenu.$buyTickets = $( '#buy-tickets' ); 12 themeTopMenu.$buyTicketsHeader = $( '#buy-tickets-header' ); 13 themeTopMenu.$menu = $( '#site-header' ); 14 15 if ( themeTopMenu.$buyTickets.length ) { 16 themeTopMenu.$buyTicketsTop = themeTopMenu.$buyTickets.offset().top; 17 } 18 19 themeTopMenu.$homePage = $( '#home-page' ); 20 themeTopMenu.$page = $( '#page' ); 21 themeTopMenu.$templatePage = $( '#template-page' ); 22 themeTopMenu.heightPromo = themeTopMenu.$templatePage.find( '.promo-block' ).height() || 0; 23 themeTopMenu.imageElement = themeTopMenu.$homePage.find( '.site-branding' ); 24 themeTopMenu.menuHeight = themeTopMenu.$menu.height(); 25 themeTopMenu.menuOuterHeight = themeTopMenu.$menu.outerHeight(); 26 themeTopMenu.submenu = $( '.customizer-top-menu-show ul.sub-menu' ); 27 themeTopMenu.fixedBuyTicketsTop = themeTopMenu.menuOuterHeight; 28 29 if ( themeUx.$body.hasClass( 'admin-bar' ) ) { 30 themeTopMenu.fixedBuyTicketsTop += 32; 31 } 32 }, 33 attachEvents: function () { 34 $( window ).resize( function () { 35 themeTopMenu.menuOuterHeight = $( '.customizer-top-menu-show ul.menu' ).outerHeight(); 36 themeTopMenu.animationTopMenu(); 37 } ); 38 39 $( window ).scroll( function () { 40 themeTopMenu.animationTopMenu(); 41 } ); 42 43 themeTopMenu.animationTopMenu(); 44 }, 45 animationTopMenu: function () { 46 if ( window.pageYOffset >= 120 ) { 47 themeTopMenu.imageElement.addClass( 'active' ); 48 } else { 49 themeTopMenu.imageElement.removeClass( 'active' ); 50 } 51 if ( window.pageYOffset >= themeTopMenu.heightPromo ) { 52 themeTopMenu.$templatePage.find( '#site-header' ).addClass( 'fixed-menu' ); 53 } else { 54 themeTopMenu.$templatePage.find( '#site-header' ).removeClass( 'fixed-menu' ); 55 } 56 } 57 }; 58})( jQuery ); 59 60(function ( $ ) { 61 window.themeBuyTickets = { 62 init: function () { 63 themeBuyTickets.initProps(); 64 themeBuyTickets.attachEvents(); 65 }, 66 initProps: function () { 67 themeBuyTickets.$datepickerModal = $( '.datepicker-modal' ); 68 themeBuyTickets.$blogPanel = $( '#blog-panel' ); 69 themeBuyTickets.$datepickerModalContainer = $( '#datepicker-modal-container' ); 70 themeBuyTickets.$dateBoxes = $( '.date-box' ); 71 themeBuyTickets.$buyTicketsHdr = $( '#buy-tickets-header' ); 72 themeBuyTickets.$dateField = $( '#buytickets-datepicker' ); 73 74 themeBuyTickets.initPicker( themeBuyTickets.$datepickerModalContainer.get( 0 ), themeBuyTickets.$dateField.get( 0 ) ); 75 }, 76 attachEvents: function () { 77 // affix the date nav when scrolled down 78 themeUx.$document.ready( themeBuyTickets.affixDateNav ); 79 themeUx.$window.on( 'resize scroll', themeBuyTickets.affixDateNav ); 80 81 // fix the datepicker modal height so it can have rounded corners 82 themeUx.$window.on( 'resize', themeBuyTickets.fixDatepickerModalHeight ); 83 84 // close the datepicker modal 85 themeBuyTickets.$datepickerModal.find( '.close-modal' ).on( 'click', themeBuyTickets.closeDatepickerModal ); 86 87 // choose a day in the days nav 88 themeBuyTickets.$dateBoxes.on( 'click', function ( e ) { 89 themeBuyTickets.onDayClick( e ); 90 } ); 91 92 $( '#buy-tickets-listview' ).find( '.no-showtimes a' ).on( 'click', function ( e ) { 93 var $dateBox = themeBuyTickets.$dateBoxes.filter( '[data-date=' + $( this ).data( 'date' ) + ']' ); 94 95 if ( $dateBox.length ) { 96 e.preventDefault(); 97 $dateBox.trigger( 'click' ); 98 } else { 99 return true; 100 } 101 } ); 102 }, 103 affixDateNav: function () { 104 var $buyTicketsHeader = $( '#buy-tickets-header' ); 105 106 if ( !$buyTicketsHeader.get( 0 ) ) { 107 return; 108 } 109 110 var $buyTicketsHeaderContainer = $( '#buy-tickets-header-container' ); 111 var $buyTicketsHeaderInner = $( '#buy-tickets-header-inner' ); 112 var winTop = themeUx.$window.scrollTop(); 113 var datepickerOffset = $buyTicketsHeaderContainer.offset().top - $( '.customizer-top-menu-show ul.menu' ).outerHeight(); 114 var newWidth = $( '#buy-tickets-listview' ).css( 'width' ); 115 var $buyTickets = $( '#buy-tickets' ); 116 117 if ( $( 'html' ).outerWidth() <= 1024 ) { 118 datepickerOffset = $buyTicketsHeaderContainer.offset().top - 44; 119 } 120 121 $( window ).resize( function () { 122 if ( $( 'html' ).outerWidth() <= 1024 ) { 123 datepickerOffset = $buyTicketsHeaderContainer.offset().top - 44; 124 } 125 } ); 126 127 if ( $( '.admin-bar' ).length === 1 ) { 128 129 if ( $( 'html' ).outerWidth() > 1024 ) { 130 datepickerOffset = $buyTicketsHeaderContainer.offset().top - ($( '.customizer-top-menu-show ul.menu' ).outerHeight() + 32); 131 } else if ( $( 'html' ).outerWidth() <= 1024 && $( 'html' ).outerWidth() > 782 ) { 132 datepickerOffset = $buyTicketsHeaderContainer.offset().top - 76; 133 } else if ( $( 'html' ).outerWidth() <= 782 ) { 134 datepickerOffset = $buyTicketsHeaderContainer.offset().top - 90; 135 } 136 137 $( window ).resize( function () { 138 if ( $( 'html' ).outerWidth() > 1024 ) { 139 datepickerOffset = $buyTicketsHeaderContainer.offset().top - ($( '.customizer-top-menu-show ul.menu' ).outerHeight() + 32); 140 } else if ( $( 'html' ).outerWidth() <= 1024 && $( 'html' ).outerWidth() > 782 ) { 141 datepickerOffset = $buyTicketsHeaderContainer.offset().top - 76; 142 } else if ( $( 'html' ).outerWidth() <= 782 ) { 143 datepickerOffset = $buyTicketsHeaderContainer.offset().top - 90; 144 } 145 } ); 146 } 147 148 if ( winTop >= datepickerOffset - 1 ) { 149 $buyTicketsHeader.addClass( 'fixed' ); 150 //$buyTicketsHeaderInner.css( 'width', newWidth ); 151 $buyTicketsHeaderContainer.css( 'padding-top', $buyTicketsHeader.outerHeight() ); 152 $buyTickets.addClass( 'fixed-header' ); 153 themeBuyTickets.$blogPanel.css( 'margin-top', '-13px' ); 154 } else { 155 $buyTicketsHeader.removeClass( 'fixed' ); 156 //$buyTicketsHeaderInner.css( 'width', '' ); 157 $buyTickets.removeClass( 'fixed-header' ); 158 159 $buyTicketsHeaderContainer.css( 'padding-top', '0' ); 160 themeBuyTickets.$blogPanel.css( 'margin-top', '0' ); 161 } 162 }, 163 fixDatepickerModalHeight: function () { 164 if ( themeBuyTickets.$datepickerModal.hasClass( 'active' ) ) { 165 var winHeight = themeUx.$window.height() - 25; 166 themeBuyTickets.$datepickerModalContainer.css( 'max-height', winHeight ); 167 } 168 }, 169 closeDatepickerModal: function () { 170 themeBuyTickets.picker.hide(); 171 themeBuyTickets.$datepickerModal.removeClass( 'active' ); 172
173 $( 'body' ).removeClass( 'modal-open' ); 174 }, 175 onDayClick: function ( e ) { 176 if ( themeBuyTickets.$buyTicketsHdr.hasClass( 'date-loading' ) ) { 177 return; 178 } 179 var $dateBox = $( e.delegateTarget ); 180 var date = $dateBox.data( 'date' ); 181 var offset = $dateBox.data( 'offset' ); 182 183 if ( $dateBox.hasClass( 'disabled' ) ) { 184 return; 185 } 186 187 themeBuyTickets.$buyTicketsHdr.addClass( 'date-loading' ); 188 themeBuyTickets.loadShowtimes( date ); 189 themeBuyTickets.selectDateNav( $dateBox ); 190 themeBuyTickets.setDateUrl( date, offset ); 191 }, 192 initPicker: function ( container, field ) { 193 if ( !container || !field || typeof themeScheduledDates === 'undefined' ) { 194 return; 195 } // no container, nothing to do 196 197 themeBuyTickets.picker = new Pikaday( { 198 field: field, 199 container: container, 200 numberOfMonths: 1, 201 minDate: new Date(), 202 maxDate: moment( window.themeScheduledDates[window.themeScheduledDates.length - 1] ).toDate(), 203 204 disableDayFn: function ( date ) { 205 return !themeBuyTickets.checkDayHasShowtimes( date ); 206 }, 207 208 onSelect: function () { 209 var selected = this.getMoment(); 210 211 themeBuyTickets.loadShowtimes( selected ); 212 themeBuyTickets.setDaysNav( selected.format() ); 213 themeBuyTickets.selectDateNav( themeBuyTickets.$dateBoxes.filter( ':first' ) ); 214 themeBuyTickets.setDateUrl( selected ); 215 216 $( '.dates-wrapper' ).addClass( 'fade-in' ); 217 $( container ).trigger( 'selected', [selected.format( 'YYYYMMDD' )] ); 218 }, 219 220 onOpen: function () { 221 themeBuyTickets.$datepickerModal.addClass( 'active' ); 222 themeUx.$body.addClass( 'modal-open' ); 223 224 var winHeight = themeUx.$window.height() - 25; 225 226 themeBuyTickets.$datepickerModalContainer.css( 'max-height', winHeight ); 227 $( '.dates-wrapper' ).removeClass( 'fade-in' ); 228 }, 229 230 onClose: function () { 231 themeBuyTickets.$datepickerModal.removeClass( 'active' ); 232 themeUx.$body.removeClass( 'modal-open' ); 233 this.destroy(); 234 themeBuyTickets.initPicker( themeBuyTickets.$datepickerModalContainer.get( 0 ), themeBuyTickets.$dateField.get( 0 ) ); 235 } 236 } ); 237 }, 238 checkDayHasShowtimes: function ( date ) { 239 var dayMoment = moment( date ); 240 return ($.inArray( dayMoment.format( 'YYYY-MM-DD' ), window.themeScheduledDates || [] ) > -1); 241 }, 242 getShowtimesUrl: function ( date ) { 243 date = !moment.isMoment( date ) ? moment( date ) : date; 244 return window.themeSettings.homeUrl + '/' + date.format( 'YYYY-MM-DD' ) + '/'; 245 }, 246 selectDateNav: function ( $dateBox ) { 247 $( '.date-box' ).removeClass( 'selected' ); 248 $dateBox.addClass( 'selected' ); 249 }, 250 loadShowtimes: function ( selected ) { 251 var $buyTicketsListview = $( '#buy-tickets-listview' ); 252 var loaderHeight = $buyTicketsListview.height(); 253 var animElTop = $buyTicketsListview.find( '.show-thumbnail:first' ).height(); 254 var $loaderContainer = $( '#loader-container' ); 255 var listOffset = $( '#buy-tickets' ).offset().top; 256 257 $loaderContainer.show(); 258 259 $( 'body, html' ).animate( { scrollTop: listOffset }, '500' ); 260 261 window.selectedDate = !moment.isMoment( selected ) ? moment( selected ) : selected; 262 263 $buyTicketsListview.empty().load( this.getShowtimesUrl( selected ) + ' .show-details', function () { 264 $loaderContainer.hide(); 265 themeUx.$window.trigger( 'resize' ); 266 themeBuyTickets.$buyTicketsHdr.removeClass( 'date-loading' ); 267 } ); 268 269 }, 270 setDaysNav: function ( firstDay ) { 271 var $dateContainers = $( '.date-box' ); 272 var currentDay = !moment.isMoment( firstDay ) ? moment( firstDay ) : firstDay; 273 274 $dateContainers.each( function ( i, e ) { 275 var dayText = ''; 276 var $e = $( e ); 277 278 if ( currentDay.format( 'DDD' ) === moment().format( 'DDD' ) ) { 279 dayText = 'Today'; 280 } else if ( currentDay.format( 'DDD' ) === moment().format( 'DDD' ) + 1 ) { 281 dayText = 'Tomorrow'; 282 } else { 283 dayText = currentDay.format( 'dddd' ); 284 } 285 286 if ( themeBuyTickets.checkDayHasShowtimes( currentDay.toDate() ) ) {
287 dayText += ' <span>' + currentDay.format( 'MMM D' ) + '</span>'; 288 $e.removeClass( 'disabled' ).attr( 'href', themeBuyTickets.getShowtimesUrl( currentDay.format( 'YYYY-MM-DD' ) ) ); 289 } else { 290 dayText += ' <span>No Showtimes</span>'; 291 $e.addClass( 'disabled' ).removeAttr( 'href' ); 292 } 293 294 $e.html( dayText ); 295 $e.data( 'date', currentDay.format( 'YYYY-MM-DD' ) ); 296 297 currentDay.add( 1, 'days' ); 298 } ); 299 }, 300 setDateUrl: function ( date, offset ) { 301 offset = offset || 0; 302 303 if ( window.history.replaceState ) { 304 window.history.replaceState( '', '', this.getShowtimesUrl( date ) + offset + '/' ); 305 } 306 } 307 }; 308})( jQuery ); 309 310/* jshint camelcase: false */ 311/* globals themeCheckout, BOOKING_FEE, Raven */ 312 313(function ( $ ) { 314 window.themeSingleShow = { 315 init: function () { 316 themeSingleShow.initProps(); 317 themeSingleShow.attachEvents(); 318 }, 319 initProps: function () { 320 themeSingleShow.$window = $( 'window' ); 321 themeSingleShow.$thumbnails = $( '.show-container' ); 322 themeSingleShow.$showtimesDescription = $( '.showtimes-description' ); 323 themeSingleShow.descriptionExpanded = false; 324 themeSingleShow.$screeningPosterThumbnail = $( '.screening-poster-thumbnail' ); 325 326 themeSingleShow.$showDetails = $( '.show-details' ); 327 themeSingleShow.$dateSelector = $( '.date-selector' ); 328 }, 329 attachEvents: function () { 330 themeUx.$window.bind( 'load scroll resize', themeSingleShow.animateThumbnails ); 331 themeUx.$window.bind( 'load', themeSingleShow.normalizePosterThumbnails ); 332 themeUx.$window.bind( 'scroll resize', themeSingleShow.stickyDatepicker ); 333 }, 334 normalizePosterThumbnails: function () { 335 themeSingleShow.$screeningPosterThumbnail.each( function () { 336 var $this = $( this ), 337 posterImgHeight = $this.find( 'img' ).height(), 338 posterHeight = $this.width() * 1.4815; 339 if ( posterHeight > posterImgHeight ) { 340 $this.addClass( 'short-poster' ); 341 } 342 } ); 343 }, 344 stickyDatepicker: function () { 345 var winTop = themeUx.$window.scrollTop(); 346 var showDetailsOffset = themeSingleShow.$showDetails.offset().top; 347 348 if ( winTop >= showDetailsOffset ) { 349 themeSingleShow.$dateSelector.addClass( 'sticky-date' ); 350 } else { 351 themeSingleShow.$dateSelector.removeClass( 'sticky-date' ); 352 } 353 } 354 }; 355})( jQuery ); 356 357(function ( $ ) { 358 'use strict'; 359 360 $( function () { 361 $( document ).on( 'click', '.date-box:not(.selected), .date-box:not(.disabled)', function () { 362 var $this = $( this ); 363 var eventFields = { 364 hitType: 'event', 365 eventCategory: 'Date Picker', 366 eventAction: 'select', 367 eventLabel: 'Buy Tickets Large', 368 eventValue: ($this.data( 'date' ) || '').replace( /\-/g, '' ) 369 }; 370 // ga( 'send', eventFields ); 371 } ); 372 373 $( document ).on( 'selected', '#datepicker-modal-container', function ( e, date ) { 374 var $this = $( this ); 375 var eventFields = { 376 hitType: 'event', 377 eventCategory: 'Date Picker', 378 eventAction: 'select', 379 eventLabel: 'Buy Tickets Calendar', 380 eventValue: date 381 }; 382 383 // ga( 'send', eventFields ); 384 } ); 385 386 $( document ).on( 'click', '.date-selector li.show-date', function ( e ) { 387 var $this = $( this ); 388 var $wrapper = $this.parents( '.date-selector' ); 389 var eventFields = { 390 hitType: 'event', 391 eventCategory: 'Date Picker', 392 eventAction: 'select', 393 eventLabel: 'Show Detail', 394 eventValue: $wrapper.data( 'show-id' ) + '.' + $this.data( 'date' ) 395 }; 396 397 // ga( 'send', eventFields ); 398 } ); 399 400 $( document ).on( 'click', '#coming-soon-header a.filter', function () { 401 var $this = $( this ); 402 var $wrapper = $this.parents( '.date-selector' ); 403 var eventFields = { 404 hitType: 'event', 405 eventCategory: 'Coming Soon Header', 406 eventAction: 'select', 407 eventLabel: $this.data( 'target' ).replace( '#', '' ) 408 }; 409 410 // ga( 'send', eventFields ); 411 } ); 412 413 $( document ).on( 'checkout-error', function ( e, info ) { 414 // send error to GA 415 if ( typeof ga !== 'undefined' ) { 416 var eventFields = { 417 hitType: 'event', 418 eventCategory: 'Checkout', 419 eventAction: info.type, 420 eventLabel: info.details 421 }; 422 423 // ga( 'send', eventFields ); 424 } 425 426 // repopulate placeholders on the form 427 if ( themeUx.$body.hasClass( 'single-membership_plan' ) || themeUx.$body.hasClass( 'membership-renew' ) ) { 428 themeMembership.updatePlaceholders(); 429 } 430 } ); 431 432 $( document ).on( 'checkout-success', function ( e, info ) { 433 // send success to GA 434 if ( typeof ga !== 'undefined' ) { 435 var eventFields = { 436 hitType: 'event', 437 eventCategory: 'Checkout', 438 eventAction: info.type, 439 eventLabel: info.details.orderId, 440 eventValue: info.details.postId 441 }; 442 // ga( 'send', eventFields ); 443 } 444 } ); 445 446 $( document ).on( 'click', 'a[data-trailer]', function () { 447 var $this = $( this ); 448 var $link = $this.parent().siblings( '.overlay-link' ); 449 var slug = ($link.attr( 'href' ) || '').match( /movies\/(.*)\/$/ ); 450 451 var eventFields = { 452 hitType: 'event', 453 eventCategory: 'Watch Trailer', 454 eventAction: 'click', 455 eventLabel: !!slug ? slug[1] : null, 456 }; 457 458 if ( typeof ga !== 'undefined' ) { 459 ga( 'send', eventFields ); 460 } 461 } ); 462 } ); 463})( jQuery ); 464 465(function ( $ ) { 466 window.themeUx = { 467 init: function () { 468 themeUx.initProps(); 469 themeUx.attachEvents(); 470 themeUx.externalTicketingLinks(); 471 472 themeBuyTickets.init(); 473 474 themeUx.initNav(); 475 476 if ( themeUx.$body.hasClass( 'page-top-menu' ) ) { 477 themeTopMenu.init(); 478 } 479 480 if ( themeUx.$body.hasClass( 'single-show' ) ) { 481 themeSingleShow.init(); 482 } 483 484 if ( (themeUx.$body.hasClass( 'checkout' ) || themeUx.$body.hasClass( 'page-template-donate-template' )) && !themeUx.$body.hasClass( 'membership-renew' ) ) {
485 themeCheckout.init(); 486 } 487 488 if ( themeUx.$body.hasClass( 'single-membership_plan' ) || themeUx.$body.hasClass( 'membership-renew' ) ) { 489 themeMembership.init(); 490 } 491 492 if ( themeUx.$body.hasClass( 'membership-update' ) ) { 493 themeMembershipUpdate.init(); 494 } 495 496 if ( themeUx.$body.hasClass( 'membership-renew' ) ) { 497 themeMembershipRenew.init(); 498 } 499 500 if ( themeUx.$body.hasClass( 'single-ticket_pack_offer' ) ) { 501 themeTicketPack.init(); 502 } 503 504 if ( null !== document.getElementById( 'virtual-cinema-panel' ) ) { 505 virtualCinemaPanel.init(); 506 } 507 508 }, 509 initProps: function () { 510 themeUx.$window = $( window ); 511 themeUx.$document = $( document ); 512 themeUx.$body = $( 'body' ); 513 themeUx.$thumbnailsContainer = $( '.thumbnails-container' ); 514 themeUx.$showDatelist = $( '.show-datelist' ); 515 themeUx.$datelist = $( '.datelist' ); 516 themeUx.$showTrailerModal = $( '.show-trailer-modal' ); 517 themeUx.$closeTrailerModal = $( '.trailer-modal .close-modal, .trailer-modal .modal-backdrop' ); 518 themeUx.$navToggle = $( '.nav-button-toggle' ); 519 themeUx.$filters = $( '.filter-container button' ); 520 themeUx.$slider = $( '.filmbot_slideshow' ); 521 themeUx.$showNewsletterModal = $( '.show-newsletter-signup-modal' ); 522 themeUx.$closeNewsletterModal = $( '.newsletter-signup-modal .close-modal, .newsletter-signup-modal .modal-backdrop' ); 523 themeUx.$primaryNav = $( '#primary-nav' ); 524 themeUx.$mobileNav = $( '#mobile-nav' ); 525 themeUx.$mobileNavLinks = themeUx.$mobileNav.find( 'a' ); 526 themeUx.$closeDatelist = $( '.mobile-close-date-selector, .show-date' ); 527 themeUx.$videoHero = $( '#video-hero' ); 528 themeUx.$scrollToAnchor = $( '.scroll-to' ); 529 themeUx.$showList = $( '.fauxselect .show-list' ); 530 themeUx.$list = $( '.fauxselect .list' ); 531 }, 532 attachEvents: function () { 533 534 themeUx.$document.on( 'keypress', function ( e ) { 535 if ( 13 === e.which ) { 536 themeUx.handleEnterKeypress( e ); 537 } 538 } ); 539 540 themeUx.$document.on( 'focus', 'input[data-fb-placeholder]', function ( e ) { 541 var $input = $( e.target ); 542 543 $input.attr( 'data-fb-placeholder', $input.attr( 'placeholder' ) ); 544 $input.attr( 'placeholder', '' ); 545 } ); 546 547 themeUx.$document.on( 'blur', 'input[data-fb-placeholder]', function ( e ) { 548 var $input = $( e.target ); 549 550 $input.attr( 'placeholder', $input.attr( 'data-fb-placeholder' ) ); 551 $input.attr( 'data-fb-placeholder', '' ); 552 } ); 553 554 themeUx.$document.on( 'click', '[role="checkbox"]', function ( e ) { 555 themeUx.handleCheckboxRoleToggle( e ); 556 } ); 557 558 // animate thumbnails 559 if ( themeUx.$thumbnailsContainer.length ) { 560 themeUx.animateThumbnails(); 561 themeUx.$window.on( 'scroll resize', themeUx.animateThumbnails ); 562 } 563 564 // open the single show date dropdowns 565 themeUx.$showDatelist.on( 'click', function ( e ) { 566 themeUx.openDatelist( e ); 567 } ); 568 569 // close the single show date dropdowns 570 themeUx.$closeDatelist.on( 'click', function ( e ) { 571 themeUx.closeDatelist( e ); 572 } ); 573 574 // select a date in the single show dropdowns 575 themeUx.$datelist.find( 'li' ).click( function ( e, initialLoad ) { 576 themeUx.selectDatelistDate( e, initialLoad ); 577 } ); 578 579 // make sure the extra and series for the first date are showing 580 themeUx.$datelist.each( function ( i, e ) { 581 $( this ).find( 'li' ).filter( ':first' ).trigger( 'click', [true] ); 582 } ); 583 584 // open trailers 585 themeUx.$document.on( 'click', '.show-trailer-modal', themeUx.openTrailerModal ); 586 587 // close trailers 588 themeUx.$document.on( 'click', '.trailer-modal .close-modal, .trailer-modal .modal-backdrop', themeUx.closeTrailerModal ); 589 590 // filters 591 themeUx.initFilters(); 592 593 themeUx.$filters.on( 'click', function ( e ) { 594 themeUx.toggleFilter( e ); 595 } ); 596 597 // sliders 598 themeUx.initializeSlider(); 599 600 // open newsletter signup modal 601 themeUx.$document.on( 'click', '.show-newsletter-signup-modal', function ( e ) { 602 themeUx.openNewsletterModal( e ); 603 } ); 604 605 // close newsletter signup modal 606 themeUx.$document.on( 'click', '.newsletter-signup-modal .close-modal, .newsletter-signup-modal .modal-backdrop', themeUx.closeNewsletterModal ); 607 608 themeUx.attachFauxselect(); 609 610 // video hero 611 themeUx.launchVideoHero(); 612 613 // check for mobile 614 themeUx.checkMobile(); 615 616 themeUx.$scrollToAnchor.on( 'click', themeUx.scrollTo ); 617 618 // Checkout section toggles. 619 themeUx.initCheckoutSectionToggles(); 620 themeUx.initCheckoutSkipToContent(); 621 622 // Change states on country change 623 themeUx.$document.on( 'change', '[data-country-selector]', function ( e ) { 624 themeUx.updateSelectableCountryStates( e ); 625 } ); 626 }, 627 /** 628 * When keypressing Enter on elements with role="link" or role="button", trigger a click. 629 * 630 * @param {object} e Original keypress event. 631 */ 632 handleEnterKeypress: function ( e ) { 633 var $el = $( e.target ); 634 var role = $el.attr( 'role' ); 635 636 if ( 'link' === role || 'button' === role || 'checkbox' === role ) { 637 $el.trigger( 'click' ); 638 } 639 }, 640 /** 641 * Toggles aria-checked attr on items using "checkbox" role. 642 * 643 * @param {object} e Original click event. 644 * 645 * @return {string} 646 */ 647 handleCheckboxRoleToggle: function ( e ) { 648 // `prevAttrValue` is always a string or undefined. 649 $( e.target ).attr( 'aria-checked', function ( i, prevAttrValue ) { 650 if ( 'undefined' === typeof prevAttrValue || 'false' === prevAttrValue ) { 651 return 'true'; 652 } 653
654 return 'false'; 655 } ); 656 }, 657 658 /** 659 * Returns modifier of requiredness of a states select field. 660 * If returned valie is undefined, then the field is not a valid states select field. 661 * If returned value is true, then selected country has states and states selector can be required, depending on form settings. 662 * If returned value is false, then selected country has no states and states selector should not be required. 663 */ 664 getStateRequirednessModifier: function ( $field ) { 665 666 // Return undefined if field is not a states select field. 667 if ( !$field.length || !$field.is( 'select' ) || !$field.data( 'state-selector' ) ) { 668 return; 669 } 670 671 var fieldId = $field.attr( 'id' ); 672 var $countriesSelector = $( '[data-country-selector="' + fieldId + '"]' ); 673 var selectedCountry = $countriesSelector.val() || 'US'; 674 var statesList = filmbotCountriesStates[selectedCountry]; 675 676 // Check if there are no states for the selected country 677 return !(Array.isArray( statesList.states ) && statesList.states.length === 0); 678 }, 679 680 /** 681 * Returns requiredness of a single field based on form settings and data attribute if it is not empty. 682 */ 683 getSingleFieldRequiredness: function ( conditions, formSettings ) { 684 // Return field requiredness based on membership type and gift/non-gift status. 685 if ( formSettings.isSingle ) { 686 return formSettings.isGift ? conditions.singleGift : conditions.default; 687 } else { 688 return formSettings.isGift ? conditions.dualGift : conditions.dual; 689 } 690 }, 691 692 /** 693 * Updates requiredness of a single field based on form settings. 694 */ 695 updateSingleFieldIsRequired: function ( $field, formSettings ) { 696 let isRequired; 697 let conditions = $field.data( 'fb-required' ); // jQuery.data() will already JSON-parse this value for us. 698 const initialRequired = $field.hasClass( 'required' ) || !!formSettings.requiredByDefault; 699 700 isRequired = conditions ? themeUx.getSingleFieldRequiredness( conditions, formSettings ) : initialRequired; 701 702 var requirednessModifier = themeUx.getStateRequirednessModifier( $field ); 703 if ( requirednessModifier !== undefined ) { 704 // If requiredness modifier is not undefined, field can be required only if modifier is true. 705 // For example: if selected country has no states, then states selector should not be required. 706 isRequired = isRequired && requirednessModifier; 707 } 708 709 // If field has error status and requiredness is changed, remove error status. 710 if ( !$field.val() && initialRequired !== isRequired ) { 711 $field.removeClass( 'error' ); 712 } 713 714 // Set requiredness class based on isRequired value. 715 $field.toggleClass( 'required', isRequired ); 716 isRequired ? $field.attr( 'required', 'required' ) : $field.removeAttr( 'required' ); 717 }, 718 719 /** 720 * Returns placeholder of a single field based on form settings and data attribute if it is not empty. 721 */ 722 getSingleFieldPlaceholder: function ( $field, formSettings ) { 723 let placeholders = $field.data( 'fb-placeholders' ); // jQuery.data() will already JSON-parse this value for us. 724 let placeholder = ''; 725 726 if ( placeholders ) { 727 if ( formSettings.isSingle ) { 728 placeholder = placeholders.single || placeholders.default || ''; 729 730 if ( formSettings.isGift ) { 731 placeholder = placeholders.singleGift || placeholders.single || placeholders.default || ''; 732 } 733 } else { 734 placeholder = placeholders.dual || placeholders.default || ''; 735 736 if ( formSettings.isGift ) { 737 placeholder = placeholders.dualGift || placeholders.dual || placeholders.default || ''; 738 } 739 } 740 } else { 741 // If field has no custom placeholders, use default placeholders (or text of empty option in select as it is what customer see). 742 placeholder = $field.is( 'select' ) ? $field.find( 'option[value=""]' ).text() : $field.attr( 'placeholder' ); 743 } 744 745 return placeholder; 746 }, 747 748 /** 749 * Updates placeholders of a single field based on form settings. 750 */ 751 updateSingleFieldPlaceholder: function ( $field, formSettings, forceCheck ) { 752 let placeholder = themeUx.getSingleFieldPlaceholder( $field, formSettings ); 753 754 var requirednessModifier = themeUx.getStateRequirednessModifier( $field ); 755 if ( requirednessModifier !== undefined || forceCheck ) { 756 let isRequired = $field.hasClass( 'required' ) || !!formSettings.requiredByDefault; 757 // If requiredness modifier is not undefined, field can be required only if modifier is true. 758 // For example: if selected country has no states, then states selector should not be required. 759 // We can use forceCheck if we need to ignore requirednessModifier (for fields that are not states- nor countries-related) 760 isRequired = (isRequired && requirednessModifier) || (isRequired && forceCheck); 761 762 // Add or remove '*' from placeholder instead of replacing whole label as it may contain different text with different capitalization. 763 764 // Remove '*' from placeholder. 765 placeholder = placeholder.replace( /\*/, '' ).trim(); 766 767 if ( isRequired ) { 768 // Add '*' to placeholder after first word. 769 placeholder = placeholder.replace( /(\w+)(.*)/, '$1* $2' ); 770 } 771 } 772 773 if ( $field.is( 'select' ) ) { 774 $field.find( 'option[value=""]' ).text( placeholder ); 775 } else { 776 $field.attr( 'placeholder', placeholder ); 777 } 778 }, 779 780 /** 781 * Updates states of selected country in states field. 782 * 783 * @param {object} e Original click event. 784 */ 785 updateSelectableCountryStates: function ( e ) { 786 var $statesFieldId = $( e.target ).data( 'country-selector' ); 787 var $statesField = $( '#' + $statesFieldId ); 788 789 if ( $statesFieldId && $statesField.length && filmbotCountriesStates ) { 790 var selectedCountry = $( e.target ).val() || 'US'; 791 var previousCountry = $statesField.data( 'state-selector' ); 792 793 var statesList = filmbotCountriesStates[selectedCountry]; 794 var prevStatesList = filmbotCountriesStates[previousCountry]; 795 796 // Check if there are no states for the selected country 797 var currentHasStates = !(Array.isArray( statesList.states ) && statesList.states.length === 0); 798 var previousHasStates = !(Array.isArray( prevStatesList.states ) && prevStatesList.states.length === 0); 799 800 // Make changes only if selected country is different from previous one 801 if ( previousCountry && previousCountry !== selectedCountry && statesList ) { 802 803 // Remove all states of previous country 804 $statesField.find( 'option[data-state]' ).remove(); 805 806 // Create new options and append them to the states field 807 $.each( statesList.states, function ( key, value ) { 808 $statesField.append( $( '<option data-state value="' + key + '">' + value + '</option>' ) ); 809 } ); 810 811 // If current country has no states, but previous had, or vice versa, 812 // update requiredness and placeholders of the states select field 813 if ( currentHasStates !== previousHasStates ) { 814 var form = $statesField.closest( 'form' ); 815 // Membership signup form has its own state with placeholders and requiredness settings 816 var isMembershipForm = form.length && form.attr( 'name' ) === 'membership-signup'; 817 var formSettings = isMembershipForm ? themeMembership.getFormSettings() : { requiredByDefault: true }; 818 // Update requiredness and placeholders of the states select field 819 themeUx.updateSingleFieldIsRequired( $statesField, formSettings ); 820 themeUx.updateSingleFieldPlaceholder( $statesField, formSettings ); 821 } 822 823 // set the new selected country as data attribute 824 $statesField.data( 'state-selector', selectedCountry ); 825 $statesField.val( '' ); 826 } 827 } 828 }, 829 attachFauxselect: function () { 830 // open the styled select dropdown 831 themeUx.$showList.on( 'click', function ( e ) { 832 themeUx.openDropdownList( e ); 833 } ); 834 835 // close the styled select dropdown 836 themeUx.$document.on( 'click', function ( e ) { 837 themeUx.closeDropdownList( e ); 838 } ); 839 }, 840 externalTicketingLinks: function () { 841 $( 'a.showtime' ).filter( function () { 842 return !!this.hostname && this.hostname !== location.hostname; 843 } ).attr( 'target', '_blank' ); 844 }, 845 animateThumbnails: function () { 846 var bottom = themeUx.$window.scrollTop() + themeUx.$window.height(); 847 848 themeUx.$thumbnailsContainer.find( '.thumbnail' ).each( function () { 849 var $this = $( this ); 850 851 if ( $this.offset().top < bottom + 20 ) { 852 $this.addClass( 'animate_active' ); 853 } 854 } ); 855 }, 856 openDatelist: function ( e ) { 857 var $dateSelector = $( e.target ).closest( '.date-selector:not(:has(.single-date))' ); 858 var $dateList = $dateSelector.find( '.datelist' ); 859 860 $dateSelector.toggleClass( 'active' ); 861 $dateList.toggleClass( 'active' ); 862 863 $dateList.find( 'li' ).each( function ( i, el ) { 864 $( el ).attr( 'tabindex', '0' ); 865 } ); 866 867 themeUx.$body.toggleClass( 'mobile-modal-open' ); 868 869 themeUx.$showDatelist.attr( 'aria-expanded', ($dateList.is( '.active' ) ? 'true' : 'false') ); 870 }, 871 closeDatelist: function ( e ) { 872 873 themeUx.$datelist.removeClass( 'active' ); 874 875 $( '.date-selector' ).removeClass( 'active' ); 876 877 var $thisDateSelector = $( e.target ).closest( '.date-selector:not(:has(.single-date))' ); 878 879 $thisDateSelector.find( 'li' ).each( function ( i, el ) { 880 $( el ).attr( 'tabindex', '-1' ); 881 } ); 882 883 themeUx.$body.removeClass( 'mobile-modal-open' ); 884 themeUx.$showDatelist.attr( 'aria-expanded', 'false' ); 885 }, 886 selectDatelistDate: function ( e, initialLoad ) { 887 var $clickedDate = $( e.target ).closest( 'li' ); 888 var $dateSelector = $clickedDate.closest( '.date-selector' ); 889 var $showtimesContainer = $dateSelector.next( '.single-show-showtimes' ).find( '.showtimes-container' ); 890 var $showContainer = $dateSelector.closest( '.show-detail
890s' ); 891 var $showtimeList = $showtimesContainer.find( '.showtime-button-row' ); 892 var selectedDate = $clickedDate.html(); 893 var date = $clickedDate.data( 'date' ); 894 895 $dateSelector.find( '.selected-date' ).html( selectedDate ); 896 $dateSelector.find( '.datelist li' ).removeClass( 'selected' ); 897 $clickedDate.addClass( 'selected' ); 898 $showContainer.find( '.extra a, .extra span, .pill' ).hide(); 899 900 if ( !initialLoad ) { 901 $showtimesContainer.hide(); 902 $showtimeList.find( 'li' ).hide(); 903 } 904 $showtimeList.find( '[data-date=' + date + ']' ).each( function ( i, showtimeLi ) { 905 const $showtime = $( showtimeLi ).find( '.showtime' ); 906 const showtimeId = $showtime.data( 'showtime_id' ); 907 $( '#showtime-extra-' + showtimeId ).show(); 908 $( '.pill.series-showtime-' + showtimeId ).show(); 909 } ).show(); 910 if ( !initialLoad ) { 911 $showtimesContainer.fadeIn( '300' ); 912 } 913 914 915 if ( $clickedDate.data( 'has-midnight' ) === 1 ) { 916 $clickedDate.closest( '.show-details' ).find( '.midnight-screening-note' ).show().css( 'display', 'flex' ); 917 } else { 918 $clickedDate.closest( '.show-details' ).find( '.midnight-screening-note' ).hide(); 919 } 920 921 }, 922 openTrailerModal: function ( e ) { 923 e.preventDefault(); 924 925 var $trailerBtn = $( this ); 926 var $trailerUrl = $trailerBtn.attr( 'data-trailer' ); 927 var $modal = $( '.trailer-modal' ); 928 929 $modal.find( '.iframe-holder-inner' ).html( $trailerUrl ); 930 $modal.addClass( 'active' ); 931 }, 932 closeTrailerModal: function () { 933 var videoContent = $( '.modal.active .iframe-holder' ).html(); 934 935 $( '.modal.active .iframe-holder' ).html( videoContent ); 936 $( '.modal.active' ).removeClass( 'active' ); 937 }, 938 initNav: function () { 939 themeUx.$navToggle.on( 'click', function ( e ) { 940 e.preventDefault(); 941 themeUx.toggleNavVisibility(); 942 } ); 943 944 themeUx.toggleNavAccessibility(); 945 946 $( window ).on( 'resize', themeUx.toggleNavAccessibility ); 947 948 // Simplebar content is dynamically added, and creates duplicates of some markup that should only be in the accessibility tree once. 949 $( '.simplebar-content' ).find( '.site-branding a, .site-branding h1, .site-branding h2' ).attr( 'tabindex', '-1' ); 950 }, 951 toggleNavVisibility: function () { 952 themeUx.$mobileNav.toggleClass( 'drawer-open' ); 953 themeUx.$body.toggleClass( 'modal-open blur-background' ); 954 themeUx.toggleNavAccessibility(); 955 }, 956 toggleNavAccessibility: function () { 957 var mobileNavOpen = themeUx.$mobileNav.is( '.drawer-open' ); 958 var primaryNavOpen = 'none' !== themeUx.$primaryNav.css( 'display' ); 959 960 if ( !primaryNavOpen ) { 961 themeUx.$navToggle.attr( 'tabindex', '0' ); 962 } else { 963 themeUx.$navToggle.attr( 'tabindex', '-1' ); 964 } 965 966 if ( mobileNavOpen ) { 967 themeUx.$navToggle.attr( 'aria-expanded', 'true' ); 968 969 themeUx.$mobileNavLinks.each( function ( i, el ) { 970 $( el ).attr( 'tabindex', '0' ); 971 } ); 972 } else { 973 themeUx.$navToggle.attr( 'aria-expanded', 'false' ); 974 975 themeUx.$mobileNavLinks.each( function ( i, el ) { 976 $( el ).attr( 'tabindex', '-1' ); 977 } ); 978 } 979 }, 980 initFilters: function () { 981 themeUx.makeInactiveFiltersInaccessible(); 982 }, 983 makeInactiveFiltersInaccessible: function () { 984 var $inactiveFilters = themeUx.$filters.filter( ':not(.selected)' ); 985 var $inactiveTargets = []; 986 987 $inactiveFilters.each( function ( i, filter ) { 988 var $filter = $( filter ); 989 var target = $filter.data( 'target' ); 990 991 $filter.attr( 'aria-selected', false ); 992 993 $inactiveTargets.push( $( target ) ); 994 } ); 995 996 $.each( $inactiveTargets, function ( i, target ) { 997 var $target = $( target ); 998 $target.add( $target.find( 'a' ) ).add( $target.find( 'h2' ) ).attr( 'tabindex', '-1' ); 999 } ); 1000 }, 1001 toggleFilter: function ( e ) { 1002 e.preventDefault(); 1003 1004 if ( target != '' ) { 1005 var $clicked = $( e.delegateTarget ); 1006 var target = $clicked.data( 'target' ); 1007 var $target = $( target ); 1008 1009 // toggle selected filter 1010 $clicked.siblings().removeClass( 'selected' ); 1011 $clicked.addClass( 'selected' ); 1012 $clicked.attr( 'aria-selected', 'true' ); 1013 1014 // toggle selected content 1015 $target.siblings().removeClass( 'active' ); 1016 $target.addClass( 'active' ); 1017 1018 // handle form fields 1019 $target.siblings().find( 'input, select' ).prop( 'disabled', true );
1020 $target.find( 'input, select' ).prop( 'disabled', false ); 1021 1022 $target.find( 'a' ).add( $target.find( 'h2' ) ).attr( 'tabindex', '0' ); 1023 1024 themeUx.makeInactiveFiltersInaccessible(); 1025 } 1026 }, 1027 initializeSlider: function () { 1028 themeUx.$slider.each( function () { 1029 var slickInduvidual = $( this ); 1030 1031 slickInduvidual.on( 'init reInit afterChange', function ( event, slick, currentSlide, nextSlide ) { 1032 console.log( slick.slideCount ); 1033 var i = (currentSlide ? currentSlide : 0) + 1; 1034 slickInduvidual.closest( '.filmbot_slideshow_container' ).find( '.counter' ).text( i + ' of ' + slick.slideCount ); 1035 } ); 1036 1037 slickInduvidual.slick( { 1038 accessibility: true, 1039 nextArrow: slickInduvidual.closest( '.filmbot_slideshow_container' ).find( '.gallery-arrow-right' ), 1040 prevArrow: slickInduvidual.closest( '.filmbot_slideshow_container' ).find( '.gallery-arrow-left' ) 1041 } ); 1042 } ); 1043 }, 1044 openNewsletterModal: function ( e ) { 1045 e.preventDefault(); 1046 1047 var $modal = $( '.newsletter-signup-modal' ); 1048 1049 $modal.addClass( 'active' ); 1050 }, 1051 closeNewsletterModal: function () { 1052 $( '.modal.active' ).removeClass( 'active' ); 1053 }, 1054 openDropdownList: function ( e ) { 1055 $( e.target ).next( '.list' ).toggleClass( 'active' ); 1056 $( 'body' ).toggleClass( 'list-active' ); 1057 }, 1058 closeDropdownList: function ( e ) { 1059 var n = $( e.target ); 1060 1061 if ( themeUx.$list.hasClass( 'active' ) ) { 1062 if ( !n.parents().hasClass( 'show-list' ) && !n.hasClass( 'show-list' ) ) { 1063 themeUx.$list.removeClass( 'active' ); 1064 } 1065 } 1066 }, 1067 selectDropdownListQuantity: function ( e ) { 1068 var $clickedItem = $( e.target ); 1069 var $dummySelectContainer = $clickedItem.closest( '.dummy-select-container' ); 1070 var $nativeSelect = $dummySelectContainer.prev( '.select-container' ).find( 'select' ); 1071 var selectedValue = $clickedItem.attr( 'data-value' ); 1072 1073 $nativeSelect.val( selectedValue ).trigger( 'change' ); 1074 }, 1075 updateDummySelect: function ( e ) { 1076 var selectedValue = $( e.target ).val(); 1077 var selectedValueDisplay = $( e.target ).find( 'option:selected' ).text(); 1078 var $dummySelectContainer = $( e.target ).closest( '.select-container' ).next( '.dummy-select-container' ); 1079 var $dummySelect = $dummySelectContainer.find( '.selected-quantity' ); 1080 1081 $dummySelect.html( selectedValueDisplay ); 1082 $dummySelectContainer.find( '.list li' ).removeClass( 'selected' ); 1083 $dummySelectContainer.find( '.list li[data-value="' + selectedValue + '"]' ).addClass( 'selected' ); 1084 }, 1085 /** 1086 * If a video hero is on the page, initialize it. 1087 */ 1088 launchVideoHero: function () { 1089 if ( !themeUx.$videoHero.length ) { 1090 return; 1091 } 1092 1093 var videoID = themeUx.$videoHero.data( 'video' ); 1094 1095 $( window ).on( 'filmbot-tubular-onPlayerReady', function () { 1096 $( '.video-hero-control' ).removeClass( 'video-hero--disabled' ); 1097 } ); 1098 1099 themeUx.$document.on( 'click', '.video-hero-play', function () { 1100 themeUx.$videoHero.addClass( 'video-hero--playing' ).removeClass( 'video-hero--paused' ); 1101 1102 } ); 1103 1104 themeUx.$document.on( 'click', '.video-hero-pause', function () { 1105 themeUx.$videoHero.addClass( 'video-hero--paused' ).removeClass( 'video-hero--playing' ); 1106 } ); 1107 1108 themeUx.$videoHero.tubular( { 1109 videoId: videoID, 1110 start: 0, 1111 mute: true, 1112 playButtonClass: 'video-hero-play', 1113 pauseButtonClass: 'video-hero-pause' 1114 } ); 1115 }, 1116 checkMobile: function () { 1117 var isMobile = /iPhone|iPad|iPod|Android/i.test( navigator.userAgent ); 1118 1119 if ( isMobile ) { 1120 themeUx.$body.addClass( 'mobile' ); 1121 } 1122 }, 1123 scrollTo: function ( e ) { 1124 e.preventDefault(); 1125 1126 var scrollToId = $( this ).attr( 'href' ); 1127 var scrollOffset = $( scrollToId ).offset().top; 1128 1129 console.log( scrollOffset ); 1130 1131 if ( themeUx.$body.hasClass( 'page-top-menu' ) ) { 1132 scrollOffset -= $( '#primary-nav' ).height(); 1133 } 1134 1135 console.log( scrollOffset ); 1136 1137 $( 'body, html' ).animate( { scrollTop: scrollOffset }, '500' ); 1138 }, 1139 /** 1140 * Inits the "Gift Card" and "Promo Code" section toggle behavior. 1141 */ 1142 initCheckoutSectionToggles: function () { 1143 1144 themeUx.$document.on( 'click', '.toggle-section-header', function ( event ) { 1145 1146 if ( !themeCheckout.$checkoutContainer.is( '.checkout-active' ) ) { 1147 return; 1148 } 1149 1150 $( this ).parent( '.row' ).toggleClass( 'toggle--opened' ); 1151 } ); 1152 }, 1153 initCheckoutSkipToContent: function () { 1154 if ( !themeUx.$body.is( '.checkout' ) ) { 1155 return; 1156 } 1157 1158 var $skipToContent = themeUx.$body.find( '#skip-to-content' ); 1159 var $seatsModal = themeUx.$body.find( '.seats-modal' ); 1160 var $paymentDetails = themeUx.$body.find( '#payment-details' ); 1161 1162 // Ensure that for checkouts without reserved seating, the Skip to Content link is available immediately. 1163 if ( !$seatsModal.length ) { 1164 $skipToContent.attr( 'tabindex', '0' ); 1165 } 1166 1167 // When a seat map's present, once it's closed make the Skip to Content link available. 1168 themeUx.$body.on( 'filmbot-seats-modal-hide', function () { 1169 $skipToContent.attr( 'tabindex', '0' ); 1170 1171 if ( window.themeCheckout.stripeElementsInit ) { 1172 window.themeCheckout.cardNumber.focus(); 1173 } 1174 } ); 1175 1176 $skipToContent.on( 'keypress', function ( e ) { 1177 if ( 13 === e.which ) { 1178 e.preventDefault(); 1179 1180 if ( window.themeCheckout.stripeElementsInit ) { 1181 window.themeCheckout.cardNumber.focus(); 1182 } 1183 } 1184 } ); 1185 } 1186 }; 1187 1188 $( themeUx.init ); 1189}) 1190( jQuery ); 1191 1192(function ( $ ) { 1193 window.themeMembership = { 1194 init: function () { 1195 themeCheckout.init(); 1196 themeMembership.initProps(); 1197 themeMembership.attachEvents(); 1198 themeCheckout.applyMembershipCosts(); 1199 themeMembership.updateRequiredFields(); 1200 themeMembership.updatePlaceholders(); 1201 themeMembership.$signupForm.css( 'visibility', 'visible' ); 1202 themeMembership.checkInitialPlanSize(); 1203 themeMembership.checkInitialPlan(); 1204 }, 1205 initProps: function () { 1206 themeMembership.$customerContainer = $( '#customer-fields' ); 1207 themeMembership.$member1Container = $( '#member-1-fields' ); 1208 themeMembership.$member2Container = $( '#member-2-fields' ); 1209 themeMembership.$customerFields = themeMembership.$customerContainer.find( '
1209input[type=text], input[type=email], select' ); 1210 themeMembership.$member1Fields = themeMembership.$member1Container.find( 'input[type=text], input[type=email], select' ); 1211 themeMembership.$member2Fields = themeMembership.$member2Container.find( 'input[type=text], input[type=email], select' ); 1212 themeMembership.$memberSelfOnlyFields = $( '[data-self-only="true"] input, [data-self-only="true"] select' ); 1213 themeMembership.$memberGiftOnlyFields = $( '[data-gift-only="true"] input, [data-gift-only="true"] select' ); 1214 themeMembership.$mailingAddressFields = $( '#mailing_address, #mailing_address_2, #mailing_city, #state, #country, #mailing_postal_code' ); 1215 themeMembership.$birthdayFields = $( '#birthday, #birthday_2' ); 1216 themeMembership.$signupForm = $( '#membership-signup form[name="membership-signup"]' ); 1217 themeMembership.$giftToggle = $( '#membership-gift-toggle [type="radio"]' ); 1218 themeMembership.$giftSendToggle = $( '#membership-gift-send-toggle [type="radio"]' ); 1219 themeMembership.$planSizeToggle = $( '#membership-plan-size-toggle [type="radio"]' ); 1220 themeMembership.$planToggle = $( '#membership-plan-toggle [type="radio"]' ); 1221 themeMembership.$paymentMethod = $( '#payment-method-select select' ); 1222 themeMembership.$selectedPlanIdField = $( '#membership_plan_current_id' ); 1223 themeMembership.$selectedSizeField = $( '#membership_plan_selected_size' ); 1224 themeMembership.$dualSwitcher = $( '#dual-switcher' ); 1225 themeMembership.$birthdayContainers = $( '.birthday-containers' ); 1226 themeMembership.$benefitsSummaries = $( '.benefits-summary' ); 1227 1228 themeMembership.initDatePickers(); 1229 }, 1230 attachEvents: function () { 1231 themeMembership.setupPaymentMethodUi(); 1232 1233 themeMembership.$giftToggle.on( 'change', themeMembership.handleGiftToggle ); 1234 themeMembership.$planSizeToggle.on( 'change', themeMembership.handlePlanSizeToggleClick ); 1235 $( '#membership_gift_send_date, #membership_gift_send_time' ).on( 'change', function () { 1236 $( 'input[name=membership_gift_send][value=scheduled]' ).prop( 'checked', 'checked' ); 1237 } ); 1238 $( '.member-gift-send-exact-date svg' ).on( 'click', function () { 1239 if ( themeMembership.pickers.sendAt ) { 1240 themeMembership.pickers.sendAt.show(); 1241 } 1242 } ); 1243 if ( themeMembership.$planToggle.length ) { 1244 themeMembership.$planToggle.on( 'change', themeMembership.handlePlanSwitchClick ); 1245 } 1246 1247 $( document ).on( 'checkout-success', themeMembership.maybeUpdateOrderConfirmationMessage ); 1248 }, 1249 /** 1250 * Enables payment method UI (e.g. switching to Cash payment method) on Membership Signup and Renewal pages. 1251 * 1252 * @returns void 1253 */ 1254 setupPaymentMethodUi: function () { 1255 if ( !themeMembership.$paymentMethod.length ) { 1256 return; 1257 } 1258 1259 themeMembership.$paymentMethod.on( 'change', function () { 1260 var pm = $( this ).val(); 1261 1262 $( '.required.error' ).toggleClass( 'error' ); 1263 1264 themeMembership.updateRequiredFields(); 1265 1266 if ( pm == 'cc' ) { 1267 $( '.payment-info' ).slideDown(); 1268 $( '#postal_code' ).slideDown(); 1269 1270 themeCheckout.$fields = themeCheckout.$fields.add( '#postal_code' ); 1271 1272 themeCheckout.showCreditCardFields(); 1273 } else if ( pm == 'cash' ) {
1274 $( '.payment-info' ).slideUp(); 1275 $( '#postal_code' ).slideUp(); 1276 1277 themeCheckout.$fields = themeCheckout.$fields.not( '#postal_code' ); 1278 1279 themeCheckout.hideCreditCardFields(); 1280 } 1281 1282 themeCheckout.paymentMethod = pm; 1283 } ); 1284 }, 1285 /** 1286 * Inits Pikaday datepickers on birthday and "send at" fields when those exist. 1287 */ 1288 initDatePickers: function () { 1289 let birthdayPickerOptions = { 1290 minDate: new Date( 'January 1, ' + (moment().get( 'year' ) - 100) ), 1291 maxDate: moment().subtract( 13, 'year' ).toDate(), 1292 yearRange: 100, 1293 format: 'MM/DD/YYYY', 1294 minYear: moment().get( 'year' ) - 100 1295 }; 1296 1297 birthdayPickerOptions.defaultDate = birthdayPickerOptions.maxDate; 1298 1299 const birthdayField = $( '#birthday' ); 1300 const birthday2Field = $( '#birthday_2' ); 1301 const giftSendDateField = $( '#membership_gift_send_date' ); 1302 const birthdayDateFormat = birthdayField.data( 'date-format' ); 1303 const birthday2DateFormat = birthday2Field.data( 'date-format' ); 1304 const giftSendDateFormat = giftSendDateField.data( 'date-format' ); 1305 1306 themeMembership.pickers = { 1307 birthday: new Pikaday( { 1308 field: birthdayField.get( 0 ), 1309 ...birthdayPickerOptions, 1310 format: birthdayDateFormat ? birthdayDateFormat : 'MM/DD/YYYY' 1311 } ), 1312 birthday2: new Pikaday( { 1313 field: birthday2Field.get( 0 ), 1314 ...birthdayPickerOptions, 1315 format: birthday2DateFormat ? birthday2DateFormat : 'MM/DD/YYYY' 1316 } ), 1317 sendAt: new Pikaday( { 1318 field: giftSendDateField.get( 0 ), 1319 defaultDate: new Date(), 1320 setDefaultDate: false, 1321 minDate: new Date(), 1322 format: giftSendDateFormat ? giftSendDateFormat : 'MM/DD/YYYY', 1323 maxDate: moment().add( 1, 'year' ).toDate() 1324 } ) 1325 }; 1326 }, 1327 /** 1328 * Updates form UI based on choosing to buy a membership for yourself or as a gift for someone else. 1329 */ 1330 handleGiftToggle: function () { 1331 themeMembership.$signupForm[0].dataset.giftMembership = $( this ).val(); 1332 1333 themeMembership.updateRequiredFields(); 1334 themeMembership.updatePlaceholders(); 1335 }, 1336 /** 1337 * Updates form UI based on choosing "single" or "dual" plan types. 1338 */ 1339 handlePlanSizeToggle: function ( planType ) { 1340 var planId = themeMembership.$selectedPlanIdField.val(); 1341 var json = $( '.membership_type_value' ).data( 'json' ); 1342 var costs = json[planId] ? json[planId]['costs'] : {}; 1343 1344 themeMembership.$signupForm[0].dataset.membershipType = planType; 1345 1346 themeMembership.$member2Container.toggle( 'dual' === planType ); 1347 1348 themeMembership.updateRequiredFields(); 1349 themeMembership.updatePlaceholders(); 1350 }, 1351 /** 1352 * Handles clicking on the "single" or "dual" plan type toggle. 1353 */ 1354 handlePlanSizeToggleClick: function () { 1355 var newSelectedSize = $( this ).val(); 1356 themeMembership.$selectedSizeField.val( newSelectedSize ); 1357 themeMembership.handlePlanSizeToggle( $( this ).val() ); 1358 }, 1359 /** 1360 * Checks the initial plan size toggle and updates the form UI accordingly. 1361 */ 1362 checkInitialPlanSize: function () { 1363 var $activeToggle = themeMembership.$planSizeToggle.filter( ':checked' ); 1364 if ( $activeToggle.length ) { 1365 themeMembership.handlePlanSizeToggle( $( $activeToggle[0] ).val() ); 1366 } 1367 }, 1368 /** 1369 * Checks the initial plan size toggle and updates the form UI accordingly. 1370 */ 1371 getCurrentMembershipSize: function () { 1372 var membershipPlanInfo = themeCheckout.getCurrentMembershipPlanInfo(); 1373 1374 if ( !membershipPlanInfo['id'] ) { 1375 return 'single'; 1376 } 1377 1378 var customerSelectedSize = themeMembership.$selectedSizeField.val(); 1379 var hasCustomerSelectedDual = 'dual' === customerSelectedSize; 1380 var isSelectedPlanSupportingDual = !!membershipPlanInfo['is_dual']; 1381
1382 return hasCustomerSelectedDual && !isSelectedPlanSupportingDual ? 'single' : customerSelectedSize; 1383 }, 1384 /** 1385 * Updates form UI based on selected offered membership plan 1386 */ 1387 handlePlanSwitch: function ( $activeToggle ) { 1388 var membershipPlanInfo = themeCheckout.getCurrentMembershipPlanInfo(); 1389 1390 if ( !membershipPlanInfo['id'] ) { 1391 return; 1392 } 1393 1394 var isSelectedPlanSupportingDual = !!membershipPlanInfo['is_dual']; 1395 var isSelectedPlanCollectingBirthdays = !!membershipPlanInfo['collect_birthdays']; 1396 1397 var updatedSelectedSize = themeMembership.getCurrentMembershipSize(); 1398 1399 isSelectedPlanSupportingDual ? themeMembership.$dualSwitcher.show() : themeMembership.$dualSwitcher.hide(); 1400 1401 isSelectedPlanCollectingBirthdays ? themeMembership.$birthdayContainers.show() : themeMembership.$birthdayContainers.hide(); 1402 1403 themeMembership.updateRequiredFields(); 1404 themeMembership.updatePlaceholders(); 1405 themeMembership.handlePlanSizeToggle( updatedSelectedSize ); 1406 themeCheckout.updateOrderMembershipSize( updatedSelectedSize ); 1407 1408 themeMembership.$benefitsSummaries.hide(); 1409 $( '[data-benefits-plan-id=' + membershipPlanInfo['id'] + ']' ).show(); 1410 1411 $( '#current-plan-single-cost' ).html( membershipPlanInfo['costs']['single'] ); 1412 $( '#current-plan-dual-cost' ).html( membershipPlanInfo['costs']['dual'] ); 1413 }, 1414 1415 /** 1416 * Handles clicking on the "single" or "dual" plan type toggle. 1417 */ 1418 handlePlanSwitchClick: function () { 1419 themeMembership.$selectedPlanIdField.val( $( this ).val() ); 1420 themeMembership.handlePlanSwitch(); 1421 }, 1422 /** 1423 * Checks the initial plan size toggle and updates the form UI accordingly. 1424 */ 1425 checkInitialPlan: function () { 1426 var $activeToggle = themeMembership.$planToggle.filter( ':checked' ); 1427 if ( $activeToggle.length ) { 1428 themeMembership.handlePlanSwitch(); 1429 } 1430 }, 1431 /** 1432 * Adds/removes fields to/from the set of required fields that must pass validation checks in themeCheckout. 1433 */ 1434 getFormSettings: function () { 1435 if ( !themeMembership.$signupForm.length ) { 1436 return { isSingle: true, isGift: false, collectAddressForGift: false }; 1437 } 1438 var isSingle = 'single' === themeMembership.$signupForm[0].dataset.membershipType; 1439 var isGift = 'true' === themeMembership.$signupForm[0].dataset.giftMembership; 1440 var collectAddressForGift = 'true' === themeMembership.$signupForm[0].dataset.collectAddressForGift; 1441 1442 return { isSingle, isGift, collectAddressForGift }; 1443 }, 1444 /** 1445 * Adds/removes fields to/from the set of required fields that must pass validation checks in themeCheckout. 1446 */ 1447 updateRequiredFields: function () { 1448 themeCheckout.$fields = themeCheckout.$fields.add( themeMembership.$customerFields ).add( themeMembership.$member1Fields ).add( themeMembership.$member2Fields ); 1449 1450 var formSettings = themeMembership.getFormSettings(); 1451 1452 if ( formSettings.isSingle ) {
1453 themeCheckout.$fields = themeCheckout.$fields.not( themeMembership.$member2Fields ); 1454 themeMembership.$member2Fields.removeClass( 'error' ); 1455 } 1456 1457 var membershipInfo = themeCheckout.getCurrentMembershipPlanInfo(); 1458 1459 if ( membershipInfo['birthdays_required'] ) { 1460 var customerSelectedSize = themeMembership.$selectedSizeField.val(); 1461 var hasCustomerSelectedDual = 'dual' === customerSelectedSize; 1462 1463 var $birthday2Field = $( '#birthday_2' ); 1464 var $birthdayFields = hasCustomerSelectedDual ? themeMembership.$birthdayFields : themeMembership.$birthdayFields.not( $birthday2Field ); 1465 themeCheckout.$fields = themeCheckout.$fields.add( $birthdayFields ); 1466 $birthdayFields.addClass( 'required' ); 1467 // Do not include birthday2 field in required fields if it is not required in the current selected membership plan 1468 if ( !hasCustomerSelectedDual ) { 1469 $birthday2Field.removeClass( 'required' ); 1470 $birthday2Field.removeClass( 'error' ); 1471 } 1472 } else { 1473 themeCheckout.$fields = themeCheckout.$fields.not( themeMembership.$birthdayFields ); 1474 themeMembership.$birthdayFields.removeClass( 'required' ); 1475 themeMembership.$birthdayFields.removeClass( 'error' ); 1476 } 1477 1478 // $birthdayFields 1479 1480 if ( formSettings.isGift ) {
1481 themeCheckout.$fields = themeCheckout.$fields.not( themeMembership.$memberSelfOnlyFields ).add( themeMembership.$giftSendToggle ); 1482 if ( formSettings.collectAddressForGift ) { 1483 themeCheckout.$fields = themeCheckout.$fields.add( themeMembership.$mailingAddressFields ); 1484 } 1485 themeMembership.$memberSelfOnlyFields.removeClass( 'error' ); 1486 } else { 1487 themeCheckout.$fields = themeCheckout.$fields.not( themeMembership.$memberGiftOnlyFields ); 1488 themeMembership.$memberGiftOnlyFields.removeClass( 'error' ); 1489 } 1490 1491 // Check fields with variable requiredness setting. This setting is stored in the data-fb-required attribute and is JSON-encoded. 1492 // It is the same as for placeholders, requiredness can be set for single/dual and gift/non-gift, as we can have field (f.e. mailing address) 1493 // required for non-gift but with different requiredness for gift. 1494 $( '[data-fb-required]' ).each( ( i, field ) => { 1495 themeUx.updateSingleFieldIsRequired( $( field ), formSettings ); 1496 } ); 1497 }, 1498 /** 1499 * Handles custom placeholder toggling on Membership Signup fields, each of which may have 2 or more possible placeholders. 1500 */ 1501 updatePlaceholders: function () { 1502 var formSettings = themeMembership.getFormSettings(); 1503 $( '[data-fb-placeholders]' ).each( ( i, field ) => { 1504 var forceCheck = false; 1505 // check if birthdays are required for the current selected membership plan 1506 if ( $( field ).hasClass( 'birthday-picker' ) ) { 1507 forceCheck = true; 1508 } 1509 themeUx.updateSingleFieldPlaceholder( $( field ), formSettings, forceCheck ); 1510 } ); 1511 }, 1512 getMember1FirstName: function () { 1513 return 'true' === themeMembership.$signupForm[0].dataset.giftMembership ? $( '#member_1_first_name' ).val() : $( '#first_name' ).val(); 1514 }, 1515 getMember1LastName: function () { 1516 return 'true' === themeMembership.$signupForm[0].dataset.giftMembership ? $( '#member_1_last_name' ).val() : $( '#last_name' ).val(); 1517 }, 1518 getMember1Email: function () { 1519 return 'true' === themeMembership.$signupForm[0].dataset.giftMembership ? $( '#member_1_email' ).val() : $( '#email' ).val(); 1520 }, 1521 getMemberData: function ( data ) { 1522 var interests = $( 'input[name="interests[]"]:checked' ).map( function ( _, el ) { 1523 return $( el ).val(); 1524 } ).get(); 1525 1526 data.member_1 = { 1527 first_name: themeMembership.getMember1FirstName(), 1528 last_name: themeMembership.getMember1LastName(), 1529 email: themeMembership.getMember1Email(), 1530 mailing_address: $( '#mailing_address' ).val(), 1531 mailing_address_2: $( '#mailing_address_2' ).val(), 1532 mailing_city: $( '#mailing_city' ).val(), 1533 mailing_state: $( '#state' ).val(), 1534 mailing_country: $( '#country' ).val(), 1535 mailing_postal_code: $( '#mailing_postal_code' ).val(), 1536 phone: $( '#phone_number' ).val(), 1537 interest: interests, 1538 acquisition_source: $( '#user-where' ).val(), 1539 }; 1540 1541 const member_1_birthday_field = $( '#birthday' ); 1542 const member_1_birthday = member_1_birthday_field.val(); 1543 let member_1_birthday_format = member_1_birthday_field.data( 'date-format' ); 1544 member_1_birthday_format = member_1_birthday_format ? member_1_birthday_format : 'MM/DD/YYYY'; 1545 1546 if ( member_1_birthday ) { 1547 data.member_1.birthdate = moment( member_1_birthday, member_1_birthday_format ).format( 'YYYY-MM-DD' ); 1548 } 1549 1550 if ( ($( '#checkout' ).length && themeCheckout.order.membership_plan.size === 'dual') || $( '#member_first_name_2' ).is( ':visible' ) ) { 1551 data.member_2 = { 1552 first_name: $( '#member_first_name_2' ).val(), 1553 last_name: $( '#member_last_name_2' ).val(), 1554 email: $( '#member_email_2' ).val(), 1555 }; 1556 1557 const member_2_birthday_field = $( '#birthday_2' ); 1558 const member_2_birthday = member_2_birthday_field.val(); 1559 let member_2_birthday_format = member_2_birthday_field.data( 'date-format' ); 1560 member_2_birthday_format = member_2_birthday_format ? member_2_birthday_format : 'MM/DD/YYYY'; 1561 1562 if ( member_2_birthday ) { 1563 data.member_2.birthdate = moment( member_2_birthday, member_2_birthday_format ).format( 'YYYY-MM-DD' ); 1564 } 1565 } 1566 1567 if ( 'true' === themeMembership.$signupForm[0].dataset.giftMembership ) { 1568 const delivery_date_field = $( '#membership_gift_send_date' ); 1569 const delivery_date = delivery_date_field.val(); 1570 let delivery_date_format = delivery_date_field.data( 'date-format' ); 1571 delivery_date_format = delivery_date_format ? delivery_date_format : 'MM/DD/YYYY'; 1572 1573 data.member_gift = { 1574 message: $( '#member_gift_message' ).val(), 1575 from_name: $( '#first_name' ).val() + ' ' + $( '#last_name' ).val(), 1576 from_email: $( '#email' ).val(), 1577 delivery: $( '[name="membership_gift_send"]:checked' ).val(), 1578 delivery_date: moment( delivery_date, delivery_date_format ).format( 'MM/DD/YYYY' ), 1579 delivery_time: $( '#membership_gift_send_time' ).val() 1580 }; 1581 } 1582 1583 if ( $( '#checkout' ).length ) { 1584 if ( themeCheckout.paymentMethod == 'cash' ) { 1585 data.address.postal_code = $( '#mailing_postal_code' ).val(); 1586 } 1587 } 1588 1589 return data; 1590 }, 1591 maybeUpdateOrderConfirmationMessage: function () { 1592 if ( 'true' === themeMembership.$signupForm[0].dataset.giftMembership ) {
1593 themeCheckout.$orderConfirmation.find( '#self-purchase-confirmation' ).hide(); 1594 themeCheckout.$orderConfirmation.find( '#gift-purchase-confirmation' ).show(); 1595 1596 if ( 'dual' === themeMembership.$signupForm[0].dataset.membershipType ) { 1597 themeCheckout.$orderConfirmation.find( '[data-membership-type="dual"]' ).show(); 1598 } 1599 } 1600 }, 1601 checkState: function () { 1602 themeMembershipUpdate.$form.find( 'select' ).each( function ( i, e ) { 1603 var $e = $( e ); 1604 var value = $( e ).data( 'selected' ); 1605 1606 if ( value !== '' ) { 1607 1608 if ( typeof value === 'string' || value instanceof String ) { 1609 value = value.replace( /(\")/g, '\\$1' ); 1610 } 1611 1612 $e.find( 'option[value="' + value + '"]' ).prop( 'selected', true ); 1613 } 1614 } ); 1615 } 1616 }; 1617})( jQuery ); 1618 1619(function ( $ ) { 1620 window.themeMembershipUpdate = { 1621 init: function () { 1622 themeMembership.initProps(); 1623 themeMembershipUpdate.initProps(); 1624 themeMembershipUpdate.attachEvents(); 1625 themeMembershipUpdate.setSelects(); 1626 }, 1627 initProps: function () { 1628 themeMembershipUpdate.$form = $( '#membership-signup' ); 1629 themeMembershipUpdate.$fields = themeMembership.$member1Fields.add( themeMembership.$member2Fields ); 1630 themeMembershipUpdate.$updateConfirmation = $( '#membership-update-confirmation' ); 1631 themeMembershipUpdate.$submitButton = $( '#submit-membership-update' ); 1632 themeMembershipUpdate.$submitError = $( '#membership-update-submit-container .submit-error' ); 1633 themeMembershipUpdate.$validateSubmitButton = $( '#submit-update-validation' ); 1634 themeMembershipUpdate.$validationError = $( '#validation-error' ); 1635 themeMembershipUpdate.$validationWindow = $( '#membership-update-validation-container' ); 1636 themeMembershipUpdate.$updatePaymentMethodButton = $( '#update-payment-method-button' ); 1637 themeMembershipUpdate.$cancelMembershipButton = $( '#cancel-membership-button' ); 1638 themeMembershipUpdate.$monthlyMembershipError = $( '#monthly-membership-error' ); 1639 themeMembershipUpdate.$monthlyMembershipPMInfo = $( '#monthly-membership-payment-method-info' ); 1640 themeMembershipUpdate.$monthlyMembershipPMImg = $( '#monthly-membership-payment-method-image' ); 1641 themeMembershipUpdate.$monthlyMembershipCardText = $( '#monthly-membership-card-text' ); 1642 themeMembershipUpdate.$monthlyMembershipCardNum = $( '#monthly-membership-card-number' ); 1643 themeMembershipUpdate.validated = themeMembershipUpdate.$form.hasClass( 'access-verified' ); 1644 }, 1645 attachEvents: function () { 1646 themeMembership.setupPaymentMethodUi(); 1647 1648 themeMembershipUpdate.$submitButton.on( 'click', themeMembershipUpdate.updateMemberDetails ); 1649 themeMembershipUpdate.$validateSubmitButton.on( 'click', themeMembershipUpdate.validateMembershipAccess ); 1650 themeMembershipUpdate.$fields.on( 'change', function () { 1651 themeMembershipUpdate.$submitButton.removeClass( 'success' ).html( 'Save' ); 1652 } ); 1653 if ( themeMembershipUpdate.$updatePaymentMethodButton.length ) { 1654 themeMembershipUpdate.$updatePaymentMethodButton.on( 'click', themeMembershipUpdate.updatePaymentMethod ); 1655 } 1656 if ( themeMembershipUpdate.$cancelMembershipButton.length ) { 1657 themeMembershipUpdate.$cancelMembershipButton.on( 'click', themeMembershipUpdate.cancelMembership ); 1658 } 1659 1660 setTimeout( function () { 1661 themeMembershipUpdate.checkPaymentMethod(); 1662 }, 2000 ); 1663 }, 1664 addFilters: function () { 1665 if ( typeof $.addFilter !== 'undefined' ) { 1666 $.addFilter( 'filmbot-modify-checkout-data', themeMembershipUpdate.updateDataByReconcileActions ); 1667 } 1668 }, 1669 updateDataByReconcileActions: function ( data ) { 1670 if ( !themeMembershipUpdate.$submitButton ) { 1671 return data; 1672 } 1673 1674 if ( data.member_1 ) { 1675 data.member_1.reconcile_action = themeMembershipUpdate.$submitButton.data( 'reconcile-action-member1' ); 1676 } 1677 1678 if ( data.member_2 ) { 1679 data.member_2.reconcile_action = themeMembershipUpdate.$submitButton.data( 'reconcile-action-member2' ); 1680 } 1681 1682 return data; 1683 }, 1684 validateMembershipUpdateForm: function () { 1685 let valid = true; 1686 1687 ['#member_email', '#member_email_2'].forEach( ( selector ) => { 1688 const $field = $( selector ); 1689 if ( !$field.length || !$field.is( ':visible' ) ) { 1690 return; 1691 } 1692 1693 if ( !$field.val() || !themeCheckout.isValidEmailAddress( $field.val() ) ) { 1694 $field.parent().addClass( 'error' ); 1695 valid = false;
1696 } else { 1697 $field.parent().removeClass( 'error' ); 1698 } 1699 } ); 1700 1701 return valid; 1702 }, 1703 updateMemberDetails: function ( e ) { 1704 if ( e ) { 1705 e.preventDefault(); 1706 } 1707 1708 if ( !themeMembershipUpdate.validated ) { 1709 return; 1710 } 1711 1712 // Do not submit the update again if already submitted 1713 if ( themeMembershipUpdate.isUpdateSubmitted ) { 1714 return; 1715 } 1716 1717 if ( !themeMembershipUpdate.validateMembershipUpdateForm() ) { 1718 themeMembershipUpdate.$submitError.text( 'Please fix the errors before continuing.' ).addClass( 'display' ); 1719 return; 1720 } 1721 1722 themeMembershipUpdate.$submitError.removeClass( 'display' ); 1723 1724 // Set flag to indicate submission in progress 1725 themeMembershipUpdate.isUpdateSubmitted = true; 1726 1727 themeMembershipUpdate.$submitButton.html( 'Please wait...' ).addClass( 'processing' ); 1728 1729 $( '#update-error' ).html( '' ); 1730 1731 var data = themeMembership.getMemberData( {} ); 1732 data = themeMembershipUpdate.getData( data ); 1733 data = themeMembershipUpdate.updateDataByReconcileActions( data ); 1734 1735 $.ajax( { 1736 method: 'POST', 1737 url: window.ajaxurl || window.themeSettings.ajaxUrl, 1738 data: data, 1739 success: function ( response ) { 1740 themeMembershipUpdate.$submitButton.removeData( 'reconcile-action-member1' ); 1741 themeMembershipUpdate.$submitButton.removeData( 'reconcile-action-member2' ); 1742 1743 if ( response === 'success' ) { 1744 themeMembershipUpdate.$submitButton.removeClass( 'processing' ).addClass( 'success' ).html( 'Update saved' ).prop( 'disabled', true ); 1745 } else { 1746 var msg = response.data ? Object.values( response.data )[0] : 'We were unable to save your details, please try again.'; 1747 1748 themeMembershipUpdate.$submitButton.removeClass( 'processing' ).html( 'Save' ); 1749 1750 // Check if we should display reconcile modals 1751 var checkResult = themeMembershipUpdate.checkIfShouldShowReconcileModals( response.data || {} ); 1752 1753 if ( checkResult.showReconcileModals ) { 1754 themeMembershipUpdate.maybeShowReconcileModals( checkResult, response.data || {}, () => { 1755 themeMembershipUpdate.updateMemberDetails(); 1756 } ); 1757 } else { 1758 // If not - display the usual error message 1759 $( '#update-error' ).html( msg ).css( 'visibility', 'visible' ); 1760 } 1761 } 1762 }, 1763 error: function () { 1764 alert( 'We were unable to save your details, please try again.' ); 1765 themeMembershipUpdate.$submitButton.removeClass( 'processing' ).html( 'Save' ); 1766 }, 1767 complete: function () { 1768 1769 // Set flag to indicate submission complete 1770 themeMembershipUpdate.isUpdateSubmitted = false; 1771 } 1772 } ); 1773 }, 1774 checkIfShouldShowReconcileModals: function ( errors ) { 1775 var errorKeys = Object.keys( errors || {} ); 1776 // Check if we need to reconcile primary member 1777 var needToReconcileMember1 = errorKeys.some( function ( key ) { 1778 return key === 'member_1_email'; 1779 } ); 1780 // Check if we need to reconcile secondary member 1781 var needToReconcileMember2 = errorKeys.some( function ( key ) { 1782 return key === 'member_2_email'; 1783 } ); 1784 // Check if there are other errors apart from member email conflicts (which require admin action) 1785 var hasOtherErrors = errorKeys.some( function ( key ) { 1786 return key !== 'member_2_email' && key !== 'member_1_email' 1787 && (key + '').indexOf( '_edit_url' ) === -1 && (key + '').indexOf( '_data' ) === -1; 1788 } ); 1789 return { 1790 needToReconcileMember1, 1791 needToReconcileMember2, 1792 showReconcileModals: !hasOtherErrors && (needToReconcileMember1 || needToReconcileMember2) 1793 }; 1794 }, 1795 maybeShowReconcileModals: function ( checkResult, errors, callback ) { 1796 // If we need to reconcile primary member and there are no other errors, show the dialog to admin 1797 if ( checkResult.showReconcileModals && checkResult.needToReconcileMember1 ) { 1798 themeMembershipUpdate.showReconcileModal( callback, errors || {}, true, checkResult.needToReconcileMember2 ); 1799 } 1800 // If we do not need to reconcile primary member, but need to reconcile secondary member and there are no other errors, show the dialog to admin
1801 if ( checkResult.showReconcileModals && !checkResult.needToReconcileMember1 && checkResult.needToReconcileMember2 ) { 1802 themeMembershipUpdate.showReconcileModal( callback, errors || {}, false ); 1803 } 1804 }, 1805 1806 /** 1807 * Shows modal dialog to logged-in user to choose how to handle email conflict situation. 1808 * In case when there are two conflicting emails (for primary and secondary members), 1809 * shows two dialogs in a row before sending the update request. 1810 * 1811 * @param isPrimaryMember 1812 * @param reconcileSecondaryMember 1813 */ 1814 showReconcileModal: function ( callback, errors, isPrimaryMember = false, reconcileSecondaryMember = false ) { 1815 var member_key = isPrimaryMember ? 'member_1' : 'member_2'; 1816 var email = errors[member_key + '_data'] || ''; 1817 var edit_url = errors[member_key + '_edit_url'] || ''; 1818 1819 // Use different text for primary vs secondary member 1820 var memberType = isPrimaryMember ? 'primary' : 'secondary'; 1821 var replaceOptionTxt = '<li><b>REPLACE</b> the ' + memberType + ' member on this membership, and keep the order histories separate.' + 1822 '<span class="action-example">Example: A different person should be the ' + memberType + ' member on this membership.</span>' + 1823 '</li>'; 1824 1825 // Show dialog to admin to choose how to handle the situation 1826 var messageHtml = '<h4 class="swal-title">Merge or Replace?</h4>' + 1827 '<p class="swal-subtitle">The email ' + email + ' is already associated with <a target="_blank" href="' + edit_url + '">an existing customer</a> with a separate order history. You can either:</p>' + 1828 '<ul class="swal-options-list">' + 1829 '<li><b>MERGE</b> the customers and their order histories into one member with this new email address.' + 1830 '<span class="action-example">Example: This is the same person with a new email address.</span>' + 1831 '</li>' + 1832 replaceOptionTxt + 1833 '</ul>'; 1834 1835 window.Swal.fire( 1836 { 1837 html: messageHtml, 1838 showCancelButton: true, 1839 showDenyButton: true, 1840 denyButtonText: 'Merge Customers', 1841 confirmButtonText: 'Replace Member', 1842 cancelButtonText: 'Cancel', 1843 customClass: { 1844 container: 'swal-admin-reconcile-customers' 1845 } 1846 } 1847 ).then( ( result ) => { 1848 // Set if we need to merge customers or just replace member by other customer 1849 var reconcileAction = result.value !== undefined ? (result.value ? 'replace' : 'merge') : undefined; 1850 var dataAttribute = isPrimaryMember ? 'reconcile-action-member1' : 'reconcile-action-member2'; 1851 1852 themeMembershipUpdate.$submitButton.data( dataAttribute, reconcileAction ); 1853 1854 // Do not continue if admin has cancelled the action 1855 if ( reconcileAction === undefined ) { 1856 $( '#update-error' ).html( '' ).css( 'visibility', 'hidden' ); 1857 1858 return; 1859 } 1860 1861 if ( isPrimaryMember && reconcileSecondaryMember ) { 1862 themeMembershipUpdate.showReconcileModal( callback, errors, false ); 1863 } else if ( typeof callback === 'function' ) { 1864 callback(); 1865 } 1866 } ); 1867 }, 1868 validateMembershipAccess: function ( e ) { 1869 e.preventDefault(); 1870 1871 themeMembershipUpdate.$validationError.removeClass( 'visible' ); 1872 themeMembershipUpdate.$validateSubmitButton.attr( 'value', 'Checking...' ); 1873 1874 $.ajax( { 1875 method: 'POST', 1876 url: window.ajaxurl || window.themeSettings.ajaxUrl, 1877 data: { 1878 action: 'fb_membership_update_validate_access', 1879 _ajax_nonce: $( '#fb_membership_update_validate_nonce' ).val(), 1880 email: $( '#membership-update-validation-form #member-email' ).val(), 1881 code: $( '#membership-update-validation-form #member-code' ).val(), 1882 membership_id: typeof window.current_membership_id != 'undefined' ? window.current_membership_id : '' 1883 }, 1884 success: function ( response ) { 1885 if ( response.success === false ) { 1886 themeMembershipUpdate.$validationError.html( response.data.join( ', ' ) ).addClass( 'visible' ); 1887 themeMembershipUpdate.$validateSubmitButton.attr( 'value', 'Continue' ); 1888 } else { 1889 themeMembershipUpdate.$validationWindow.css( 'height', '0px' ); 1890 themeMembershipUpdate.$form.removeClass( 'access-not-verified' ); 1891 themeMembershipUpdate.validated = true; 1892 } 1893 } 1894 } ); 1895 }, 1896 updatePaymentMethod: function ( e ) { 1897 e.preventDefault(); 1898 1899 themeMembershipUpdate.$monthlyMembershipError.removeClass( 'visible' ); 1900 themeMembershipUpdate.$updatePaymentMethodButton.html( 'Redirecting...' ); 1901 themeMembershipUpdate.$updatePaymentMethodButton.prop( 'disabled', true ); 1902 1903 $.ajax( { 1904 method: 'POST', 1905 url: window.ajaxurl || window.themeSettings.ajaxUrl, 1906 data: { 1907 action: 'fb_create_update_payment_method_stripe_portal_session', 1908 _ajax_nonce: $( '#fb_membership_update_nonce' ).val(), 1909 membership_id: typeof window.current_membership_id != 'undefined' ? window.current_membership_id : '' 1910 }, 1911 success: function ( response ) { 1912 if ( response.success === true ) { 1913 window.location = response.url; 1914 } else { 1915 themeMembershipUpdate.$monthlyMembershipError.html( response.data.join( ', ' ) ).addClass( 'visible' ); 1916 themeMembershipUpdate.$updatePaymentMethodButton.html( 'Update Payment Method' ); 1917 themeMembershipUpdate.$updatePaymentMethodButton.prop( 'disabled', false ); 1918 } 1919 } 1920 } ); 1921 }, 1922 cancelMembership: function ( e ) { 1923 e.preventDefault(); 1924 1925 var banWarningMessage = themeMembershipUpdate.$cancelMembershipButton.data( 'ban-warning' ); 1926 if ( !banWarningMessage ) { 1927 themeMembershipUpdate.cancelMembershipConfirmed(); 1928 } else { 1929 window.Swal.fire( 1930 { 1931 html: banWarningMessage, 1932 showCancelButton: true, 1933 confirmButtonText: 'Cancel renewal', 1934 confirmButtonColor: '', 1935 cancelButtonText: 'Never mind', 1936 cancelButtonColor: '', 1937 } 1938 ).then( ( result ) => { 1939 if ( result.value == true ) { 1940 themeMembershipUpdate.cancelMembershipConfirmed(); 1941 } 1942 } ); 1943 } 1944 }, 1945 cancelMembershipConfirmed: function () { 1946 themeMembershipUpdate.$monthlyMembershipError.removeClass( 'visible' ); 1947 themeMembershipUpdate.$cancelMembershipButton.html( 'Cancelling...' ); 1948 themeMembershipUpdate.$cancelMembershipButton.prop( 'disabled', true ); 1949 1950 $.ajax( { 1951 method: 'POST', 1952 url: window.ajaxurl || window.themeSettings.ajaxUrl, 1953 data: { 1954 action: 'fb_cancel_membership_subscription', 1955 _ajax_nonce: $( '#fb_membership_update_nonce' ).val(), 1956 membership_id: typeof window.current_membership_id ? window.current_membership_id : '' 1957 }, 1958 success: function ( response ) { 1959 if ( response.success === true ) { 1960 window.location = response.url; 1961 } else { 1962 themeMembershipUpdate.$monthlyMembershipError.html( response.data.join( ', ' ) ).addClass( 'visible' ); 1963 themeMembershipUpdate.$cancelMembershipButton.html( 'Cancel Renewal' ); 1964 themeMembershipUpdate.$cancelMembershipButton.prop( 'disabled', false ); 1965 } 1966 } 1967 } ); 1968 }, 1969 checkPaymentMethod: function () { 1970 if ( !themeMembershipUpdate.$monthlyMembershipPMInfo.length ) { 1971 return; 1972 } 1973 1974 $.ajax( { 1975 method: 'POST', 1976 url: window.ajaxurl || window.themeSettings.ajaxUrl, 1977 data: { 1978 action: 'fb_check_membership_payment_method', 1979 _ajax_nonce: $( '#fb_membership_update_nonce' ).val(), 1980 membership_id: typeof window.current_membership_id != 'undefined' ? window.current_membership_id : '' 1981 }, 1982 success: function ( response ) { 1983 if ( response.success === true ) { 1984 themeMembershipUpdate.$monthlyMembershipPMImg.hide(); 1985 themeMembershipUpdate.$monthlyMembershipCardText.hide(); 1986 1987 if ( response.data.payment_method_image ) { 1988 themeMembershipUpdate.$monthlyMembershipPMImg.attr( 'src', response.data.payment_method_image ); 1989 themeMembershipUpdate.$monthlyMembershipPMImg.attr( 'alt', response.data.card_brand ? response.data.card_brand : response.data.type ); 1990 themeMembershipUpdate.$monthlyMembershipPMImg.show(); 1991 } 1992 1993 if ( response.data.card_number ) { 1994 themeMembershipUpdate.$monthlyMembershipCardNum.html( response.data.card_number ); 1995 themeMembershipUpdate.$monthlyMembershipPMInfo.removeClass( 'other-payment-method' ); 1996 themeMembershipUpdate.$monthlyMembershipCardText.show(); 1997 } else { 1998 themeMembershipUpdate.$monthlyMembershipPMInfo.addClass( 'other-payment-method' ); 1999 } 2000 } 2001 } 2002 } ); 2003 }, 2004 getData: function ( data ) { 2005 data.member_1.first_name = $( '#member_first_name' ).val(); 2006 data.member_1.last_name = $( '#member_last_name' ).val(); 2007 data.member_1.email = $( '#member_email' ).val(); 2008 data.action = 'fb_membership_update'; 2009 data.membership_id = window.current_membership_id || ''; 2010 data._ajax_nonce = $( '#fb_membership_update_nonce' ).val(); 2011 data.order = $.extend( data.order ?? {}, { email: data.member_1.email } ); 2012 2013 if ( (data.member_2 ?? []).length || data.order?.membership_plan?.size === 'dual' ) { 2014 data.member_2.first_name = $( '#member_first_name_2' ).val(); 2015 data.member_2.last_name = $( '#member_last_name_2' ).val(); 2016 data.member_2.email = $( '#member_email_2' ).val(); 2017 } 2018 return data; 2019 }, 2020 setSelects: function () { 2021 themeMembershipUpdate.$form.find( 'select' ).each( function ( i, e ) { 2022 var $e = $( e ); 2023 var value = $( e ).data( 'selected' ); 2024 2025 if ( value !== '' ) { 2026 2027 if ( typeof value === 'string' || value instanceof String ) { 2028 value = value.replace( /(\")/g, '\\$1' ); 2029 } 2030 2031 $e.find( 'option[value="' + value + '"]' ).prop( 'selected', true ); 2032 } 2033 } ); 2034 } 2035 }; 2036})( jQuery ); 2037 2038(function ( $ ) { 2039 window.themeMembershipRenew = { 2040 init: function () { 2041 themeMembershipUpdate.$form = $( '#membership-signup' ); 2042 themeMembershipUpdate.$validateSubmitButton = $( '#submit-update-validation' ); 2043 themeMembershipUpdate.$validationWindow = $( '#membership-update-validation-container' ); 2044 themeMembershipUpdate.$validationError = $( '#validation-error' ); 2045 themeMembershipUpdate.$form.removeClass( 'access-not-verified' ); 2046 themeMembershipUpdate.validated = true; 2047 themeMembershipUpdate.$validateSubmitButton.on( 'click', themeMembershipUpdate.validateMembershipAccess ); 2048 } 2049 }; 2050})( jQuery ); 2051 2052 2053(function ( $ ) { 2054 window.themeTicketPack = { 2055 init: function () { 2056 themeCheckout.init(); 2057 themeTicketPack.initProps(); 2058 themeTicketPack.attachEvents(); 2059 themeCheckout.applyTicketPackCosts(); 2060 }, 2061 initProps: function () { 2062 themeTicketPack.$paymentMethod = $( '#payment-method-select select' ); 2063 }, 2064 attachEvents: function () { 2065 if ( themeTicketPack.$paymentMethod.length ) { 2066 themeTicketPack.$paymentMethod.on( 'change', function () { 2067 var pm = $( this ).val(); 2068 // When the payment method changes, reset the errors. 2069 $( '.required.error' ).toggleClass( 'error' ); 2070 // Toggle credit card fields 2071 if ( pm === 'cc' ) { 2072 $( '.payment-info' ).slideDown(); 2073 $( '#postal_code' ).slideDown(); 2074
2075 themeCheckout.$fields = themeCheckout.$fields.add( '#postal_code' ); 2076 2077 themeCheckout.showCreditCardFields(); 2078 } else if ( pm === 'cash' ) { 2079 $( '.payment-info' ).slideUp(); 2080 $( '#postal_code' ).slideUp(); 2081 2082 themeCheckout.$fields = themeCheckout.$fields.not( '#postal_code' ); 2083 2084 themeCheckout.hideCreditCardFields(); 2085 } 2086 themeCheckout.paymentMethod = pm; 2087 } ); 2088 } 2089 }, 2090 }; 2091})( jQuery ); 2092 2093(function ( $ ) { 2094 window.virtualCinemaPanel = { 2095 init: function () { 2096 2097 virtualCinemaPanel.cacheSections(); 2098 2099 $( window ).on( 'load', virtualCinemaPanel.equalizePosterHeights ); 2100 $( window ).on( 'resize', virtualCinemaPanel.equalizePosterHeights ); 2101 }, 2102 cacheSections: function () { 2103 virtualCinemaPanel.sections = []; 2104 2105 $( '.virtual-cinema__section' ).each( function ( i, section ) { 2106 virtualCinemaPanel.sections[i] = section; 2107 } ); 2108 }, 2109 equalizePosterHeights: function () { 2110 2111 $.each( virtualCinemaPanel.sections, function ( i, section ) { 2112 const $posters = $( section ).find( '.virtual-cinema__movie img' ); 2113 let maxHeight = 0; 2114 2115 $posters.each( function ( j, poster ) { 2116 if ( $( poster ).height() > maxHeight ) { 2117 maxHeight = $( poster ).height(); 2118 } 2119 } ); 2120 2121 $posters.each( function ( j, poster ) { 2122 $( poster ).css( 'min-height', maxHeight ); 2123 } ); 2124 } ); 2125 2126 } 2127 }; 2128})( jQuery ); 2129 2130//# sourceMappingURL=development.js.map
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.