PageSourceSearch

https://tickets.balletedmonton.ca/js/main.1788259773.js

js balletedmonton.ca collected 2026-09-30 11:28:25 UTC 12,013 bytes, 361 lines download raw bytes

1var fbUserData = null;
2var numAttendingFriends = 0;
3var dripCartCreated = false;
4
5//fallback in case global translated strings are not in memory
6if (typeof shareText == 'undefined') {
7	var shareText = 'Share on';
8	var calendarText = 'Calendar';
9	var cookieText = 'Please enable cookies in your browser to proceed.';
10}
11
12$(document).ready(function() {
13
14	$(".galleryPhoto a").fancybox();
15	$(".classicEventLogo a").fancybox();
16	$(".activity-preview a").fancybox({type: 'ajax'});
17
18	 // Disable Fancybox hash/history updates to avoid browser navigation / page refreshing when closing a fancybox opened from an <a> link
19	if ($.fancybox && $.fancybox.defaults) {
20		$.fancybox.defaults.hash = false;
21	}
22
23	$('.sharethisArea a.btn_share_facebook').on("click",function(e) {
24		e.preventDefault();
25		PopupCenter($(this).attr('href'), shareText + ' Facebook', 550, 450);
26		return false;
27	});
28
29	$('#fb-whos-going-area a#btn-fb-connect-share').on("click",function(e) {
30		e.preventDefault();
31		PopupCenter($(this).attr('href'), shareText + ' Facebook', 550, 450);
32		return false;
33	});
34
35	$('.sharethisArea a.btn_share_twitter').on("click",function(e) {
36		e.preventDefault();
37		PopupCenter($(this).attr('href'), shareText + ' Twitter', 550, 450);
38		return false;
39	});
40
41	$('.sharethisArea a.btn_share_google-plus').on("click",function(e) {
42		e.preventDefault();
43		PopupCenter($(this).attr('href'), shareText + ' Google+', 680, 460);
44		return false;
45	});
46
47	$('.sharethisArea a.btn_share_linkedin').on("click",function(e) {
48		e.preventDefault();
49		PopupCenter($(this).attr('href'), shareText + ' LinkedIn', 680, 460);
50		return false;
51	});
52
53	// <!-- AddThisEvent Settings -->
54	addthisevent.settings({
55		mouse       : false,
56		css         : false,
57		outlook     : {show:true, text:"Outlook " + calendarText},
58		google      : {show:true, text:"Google " + calendarText},
59		yahoo       : {show:true, text:"Yahoo " + calendarText},
60		ical        : {show:true, text:"iCal " + calendarText},
61		hotmail     : {show:true, text:"Hotmail " + calendarText},
62		facebook    : {show:true, text:"Facebook " + calendarText}
63	});
64
65	$('input[required="required"]').addClass('required');
66	$('select[required="required"]').addClass('required');
67
68	$(".btn_help").fancybox({
69		'transitionIn'	:	'elastic',
70		'transitionOut'	:	'elastic',
71		'speedIn'		:	1000,
72		'speedOut'		:	1000,
73		'overlayShow'	:	false,
74		'autoSize'      :   false,
75		'afterClose'    :   function(){cancelmessage();}
76	});
77
78	var sendCartAbandonEmail = typeof abandonEnabled !== 'undefined' && abandonEnabled;
79
80	// Handle abandonment / drip triggers on tickets page
81	$("#orderForm #OrderEmail").on('focusout', function() {
82		// check that is a valid email format
83		var testEmail = /^[A-Z0-9._%+-]+@([A-Z0-9-]+\.)+[A-Z]{2,4}$/i;
84		if (testEmail.test($(this).val())){
85			recordOrderAttempt(sendCartAbandonEmail);
86		}
87	});
88
89});
90
91// Meta browser (_fbp) and click (_fbc) IDs, both formatted fb.<subdomainIndex>.<creationMs>.<value>
92const META_BROWSER_ID_COOKIE = '_fbp';
93const META_CLICK_ID_COOKIE = '_fbc';
94const META_CLICK_ID_MAX_AGE_SECONDS = 90 * 24 * 60 * 60;
95const META_BROWSER_ID_POLL_ATTEMPTS = 10;
96const META_BROWSER_ID_POLL_DELAY_MS = 100;
97
98/**
99 * Reads a cookie value by name.
100 * @param {string} name cookie name
101 * @return {string} the decoded value, or '' when the cookie is not set or its value is malformed
102 */
103function readCookieValue(name) {
104	const escapedName = name.replace(/[-.^$*+?()[\]{}|\\]/g, '\\$&');
105	const match = document.cookie.match(new RegExp(`(?:^|;\\s*)${escapedName}=([^;]*)`));
106	if (!match) {
107		return '';
108	}
109
110	try {
111		return decodeURIComponent(match[1]);
112	} catch {
113		// A malformed value written by another script must not break the calling handler
114		return '';
115	}
116}
117
118/**
119 * Resolves the Meta click ID (_fbc). Builds it from the fbclid URL parameter
120 * when the cookie is missing or holds an older click, which happens when an ad
121 * blocker stops fbevents.js from loading (the Pixel would otherwise write and
122 * refresh the cookie itself). Persists what it builds so later steps in the
123 * checkout funnel still carry the click ID.
124 * @return {string} the _fbc value, or '' when there is no click to attribute
125 */
126function resolveMetaClickId() {
127	const fbclid = new URLSearchParams(window.location.search).get('fbclid');
128	const existingClickId = readCookieValue(META_CLICK_ID_COOKIE);
129
130	// A differing fbclid means a newer ad click: refresh the cookie the way the
131	// Pixel would, rather than letting a stale click ID win for its 90-day life
132	if (!fbclid || (existingClickId && existingClickId.endsWith(`.${fbclid}`))) {
133		return existingClickId;
134	}
135
136	// Meta specifies a subdomain index of 1 when the value is generated outside the Pixel.
137	// No domain attribute, so this stays host-only: the registrable domain cannot be derived
138	// safely in JS across this platform's white-label domains.
139	const clickId = `fb.1.${Date.now()}.${fbclid}`;
140	const secureFlag = window.location.protocol === 'https:' ? '; secure' : '';
141	document.cookie = `${META_CLICK_ID_COOKIE}=${encodeURIComponent(clickId)}; max-age=${META_CLICK_ID_MAX_AGE_SECONDS}; path=/; samesite=lax${secureFlag}`;
142
143	return clickId;
144}
145
146/**
147 * Reads the Meta browser ID (_fbp), retrying briefly because the Meta Pixel
148 * writes it only once fbevents.js has loaded, which can land after our first
149 * ViewContent call.
150 * @param {number} attemptsLeft remaining reads before giving up
151 * @param {function} onResolved receives the _fbp value, or '' if it never appears
152 */
153function readMetaBrowserId(attemptsLeft, onResolved) {
154	const browserId = readCookieValue(META_BROWSER_ID_COOKIE);
155	if (browserId || attemptsLeft <= 1) {
156		onResolved(browserId);
157		return;
158	}
159
160	setTimeout(() => readMetaBrowserId(attemptsLeft - 1, onResolved), META_BROWSER_ID_POLL_DELAY_MS);
161}
162
163// XHR call for Meta Conversions API
164function postMetaConversions(metaData) {
165	// Copy so the fbc/fbp writes below stay off the caller's object, and so a
166	// caller that later mutates its payload can't race the _fbp wait
167	const payload = Object.assign({}, metaData);
168
169	// Resolved up front so the _fbc cookie is written even if the visitor
170	// navigates away while we are still waiting on _fbp
171	payload.fbc = resolveMetaClickId();
172
173	readMetaBrowserId(META_BROWSER_ID_POLL_ATTEMPTS, (browserId) => {
174		payload.fbp = browserId;
175
176		$.ajax({
177			type: "POST",
178			url: buildURL('/external_apis/ajax_post_meta_conversions'),
179			data: payload,
180			dataType: "json"
181		});
182	});
183}
184
185// adds partner channel and track to a javascript-written URL if needed
186function buildURL(sURL) {
187	if(partnerTrack) {
188		sURL = '/' + partnerTrack + sURL;
189	}
190	if(partnerChannel) {
191		sURL = '/' + partnerChannel + sURL;
192	}
193	return sURL;
194}
195
196
197
198function PopupCenter(url, title, w, h) {
199    // Fixes dual-screen position                         Most browsers      Firefox
200    var dualScreenLeft = window.screenLeft != undefined ? window.screenLeft : screen.left;
201    var dualScreenTop = window.screenTop != undefined ? window.screenTop : screen.top;
202
203    width = window.innerWidth ? window.innerWidth : document.documentElement.clientWidth ? document.documentElement.clientWidth : screen.width;
204    height = window.innerHeight ? window.innerHeight : document.documentElement.clientHeight ? document.documentElement.clientHeight : screen.height;
205
206    var left = ((width / 2) - (w / 2)) + dualScreenLeft;
207    var top = ((height / 2) - (h / 2)) + dualScreenTop;
208    var newWindow = window.open(url, title, 'scrollbars=yes, status=no, toolbar=no, location=no, menubar=no, directories=no, width=' + w + ', height=' + h + ', top=' + top + ', left=' + left);
209
210    // Puts focus on the newWindow
211    if (window.focus) {
212        newWindow.trigger("focus");
213    }
214}
215
216/**
217 * When a video thumbnail is selected in the video module, this highlights it, and loads it into the top iframe
218 * @param  {[type]} youtubeUrl [description]
219 * @return {[type]}            [description]
220 */
221function loadTopVideo(galleryId, videoId, videoType, videoPlayerId) {
222    switch(videoType){
223        case 'youtube':
224            $('#' + galleryId + '_iframe').attr('src', '//www.youtube.com/embed/' + videoId);
225            $('#' + galleryId + ' .thumb').removeClass('at');
226            $('#' + galleryId + '_thumb'+youtubeUrl).addClass('at');
227            break;
228        case 'brightcove':
229            $('#' + galleryId + '_iframe').attr('src', 'https://players.brightcove.net/' + videoPlayerId + '/default_default/index.html?videoId=' + videoId);
230            $('#' + galleryId + ' .thumb').removeClass('at');
231            $('#' + galleryId + '_thumb'+youtubeUrl).addClass('at');
232            break;
233    }
234}
235
236/**
237 * [wideReloadVideoFrame video selection UI controls for the Wide Format Layout]
238 * @param  {[type]} videoId [description]
239 * @return {[type]}           [description]
240 */
241function wideReloadVideoFrame(type, videoId, playerId){
242    switch(type){
243        case "youtube":
244            $("#videoFrame").attr("src", "https://www.youtube.com/embed/" + videoId);
245            break;
246        case "brightcove":
247            $("#videoFrame").attr("src", "https://players.brightcove.net/" + playerId + "/default_default/index.html?videoId=" + videoId);
248            break;
249    }
250    $("#thumb_" + videoId).addClass("v_active");
251    $(".video_thumb").not("#thumb_" + videoId).removeClass("v_active");
252    var hgt = $('.video_thumb').height() * ($('#videoFrame').width() / $('.video_thumb').width());
253    //using .css to avoid a bug in MS Edge - the .height() attribute doesn't set reliably that way
254    $('#videoFrame').css('height',hgt);
255    $('.player').css('height',hgt);
256}
257
258/**
259 * [alertCookiesRequired]
260 * @return {[type]}           [description]
261 */
262function alertCookiesRequired() {
263	if (!navigator.cookieEnabled) {
264		alert(cookieText);
265	}
266}
267
268/**
269 * Send Cart data to Drip and/or CartAbandonment email
270 * if we haven't already done so for this email address
271 * @param  {[type]} videoId [description]
272 * @return {[type]}           [description]
273 */
274async function recordOrderAttempt(sendCartAbandonEmail) {
275	var runAjax = false;
276	if($('#OrderEmail').length > 0){
277		// check if we need to run the ajax call
278		if($('#OrderEmailBackedUp').length > 0 && $('#OrderEmailBackedUp').val() == $('#OrderEmail').val()){
279			// do not need to run the ajax again
280		} else {
281			// it has changed, need to run the ajax again
282			runAjax = true;
283		}
284	} else {
285		// run the ajax call
286		runAjax = true;
287	}
288	if (!runAjax) {
289		return;
290	}
291	if (sendCartAbandonEmail) {
292		$.ajax({
293			type: "POST",
294			url: buildURL("/abandonments/ajax_record_order_attempt"),
295			data: $("#orderForm").serialize(),
296			dataType: "json",
297			success: function (data) {
298				if(data.success) {
299					if($('#OrderEmailBackedUp').length > 0 && $('#OrderEmailBackedUp').val()){
300						$('#OrderEmailBackedUp').val(data.email);
301					} else {
302						$('<input>', {
303							type: 'hidden',
304							id: 'OrderEmailBackedUp',
305							name: 'data[Order][email_backed_up]',
306							value: data.email
307						}).appendTo('#orderForm');
308					}
309				} else {
310					// did not process
311				}
312				// if we need to do anything on this side
313			}
314		});
315	}
316
317	if (dripEnabled) {
318		sendCartDataToDrip('created', 'cart');
319	}
320}
321
322function sendCartDataToDrip(action, type) {
323	if (action == 'created' && dripCartCreated) {
324		// runAjax check above doesn't always seem to work
325		return false;
326	}
327
328	// custom drip payload
329	const dripParams = {
330		dripEntity: type,
331		dripAction: action,
332		ticketsPage: window.location.href,
333		currency: currency, // defined on ticket page(s)
334	}
335
336	const additionalParams = Object.keys(dripParams)
337		.map(k => `&${k}=${dripParams[k]}`)
338		.join('');
339
340	// Send to Drip
341	$.ajax({
342		type: "POST",
343		url: buildURL("/external_apis/ajax_post_drip_cart_activity"),
344		data:  $("#orderForm").serialize() + additionalParams,
345		dataType: "json",
346		success: function () {
347			if (!dripCartCreated) {
348				dripCartCreated = true;
349			}
350			return true;
351		}
352	});
353}
354
355function updateDripCart() {
356	if (!dripCartCreated || !dripEnabled) {
357		return;
358	}
359
360	sendCartDataToDrip('updated', 'cart');
361}

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.