PageSourceSearch

https://mediaartscenter.org/content/themes/marquee/assets/js/theme.js?ver=9a8b449f

js mediaartscenter.org collected 2026-09-24 18:49:29 UTC 79,956 bytes, 2,130 lines download raw bytes

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.