PageSourceSearch

https://rhcl.org/js/custom.js?v=1480

js rhcl.org collected 2026-09-26 03:50:59 UTC 195,359 bytes, 5,412 lines download raw bytes

1/*jslint browser: true*/
2/*global $, jQuery*/
3var googleAutocompleteMapObject = null;
4
5function skipToMainContent(targetSelector) {
6	var $target = targetSelector ? $(targetSelector).first() : $();
7	var targetElement = $target.length ? $target.get(0) : null;
8	if ($target.length === 0 || !targetElement || !targetElement.focus) {
9		return true;
10	}
11	if (!$target.is('[tabindex]')) {
12		$target.attr('tabindex', '-1').attr('data-skip-main-focus', '1');
13	}
14	if (window.history && window.history.pushState) {
15		window.history.pushState(null, document.title, targetSelector);
16	} else {
17		window.location.hash = targetSelector;
18	}
19	window.setTimeout(function () {
20		if (targetElement.scrollIntoView) {
21			targetElement.scrollIntoView();
22		}
23		targetElement.focus();
24	}, 0);
25	$target.one('blur', function () {
26		if ($(this).attr('data-skip-main-focus') === '1') {
27			$(this).removeAttr('tabindex').removeAttr('data-skip-main-focus');
28		}
29	});
30	return false;
31}
32
33function initClassicEmbeddedPage(options) {
34	var settings = $.extend({
35		enabled: false,
36		source: '',
37		hostSource: '',
38		parentOrigin: '',
39		requireEmbedSource: false,
40		embedSource: '',
41		rewriteInternalLinks: false,
42		observeMutations: true
43	}, options || {});
44	var rewriteFrame = 0;
45	var heightFrame = 0;
46	var processedLinkAttribute = 'data-embedded-nav-processed';
47
48	if (!settings.enabled) {
49		return;
50	}
51
52	var hasParent = window.parent && window.parent !== window;
53	var canPostToParent = !!settings.parentOrigin && hasParent;
54	if (settings.requireEmbedSource) {
55		canPostToParent = canPostToParent && /^create-classic-/.test(settings.embedSource || '');
56	}
57
58	var postToParent = function (type, payload) {
59		if (!canPostToParent) {
60			return;
61		}
62		window.parent.postMessage({
63			source: settings.source,
64			type: type,
65			payload: payload || {}
66		}, settings.parentOrigin);
67	};
68
69	var scheduleHeightPost = function () {
70		if (heightFrame) {
71			return;
72		}
73		heightFrame = window.requestAnimationFrame(function () {
74			heightFrame = 0;
75			var body = document.body;
76			var docEl = document.documentElement;
77			var height = Math.max(
78				body ? body.scrollHeight : 0,
79				body ? body.offsetHeight : 0,
80				body ? Math.ceil(body.getBoundingClientRect().height) : 0,
81				docEl ? docEl.offsetHeight : 0
82			);
83			$('.amPopup:visible, .popupwidget:visible, .events2-reg-popup:visible').each(function () {
84				var rect = this.getBoundingClientRect();
85				var popupBottom = Math.ceil(rect.bottom + window.scrollY);
86				if (popupBottom > height) {
87					height = popupBottom;
88				}
89			});
90			height += 8;
91			postToParent('height-update', { height: height });
92		});
93	};
94
95	var scheduleRewriteInternalLinks = function () {
96		if (rewriteFrame) {
97			return;
98		}
99		rewriteFrame = window.requestAnimationFrame(function () {
100			rewriteFrame = 0;
101			rewriteInternalLinks();
102		});
103	};
104
105	var resolveInternalHref = function (href) {
106		if (!href || href.charAt(0) === '#') {
107			return '';
108		}
109		try {
110			var url = new URL(href, window.location.origin);
111			if (url.origin !== window.location.origin) {
112				return '';
113			}
114			return url.pathname + url.search + url.hash;
115		} catch (error) {
116			return '';
117		}
118	};
119
120	var rewriteInternalLinks = function () {
121		if (!settings.rewriteInternalLinks || !canPostToParent) {
122			return;
123		}
124		$('a[href]').each(function () {
125			var $link = $(this);
126			if ($link.attr(processedLinkAttribute) === '1') {
127				return;
128			}
129			var pathAndQuery = resolveInternalHref($link.attr('href'));
130			if (!pathAndQuery) {
131				return;
132			}
133			$link.attr('data-embedded-nav-path', pathAndQuery);
134			$link.attr('href', pathAndQuery);
135			$link.attr(processedLinkAttribute, '1');
136		});
137	};
138
139	if (settings.rewriteInternalLinks) {
140		$(document).off('click.classicEmbeddedNavigate').on('click.classicEmbeddedNavigate', 'a[data-embedded-nav-path]', function (event) {
141			if (!canPostToParent || event.metaKey || event.ctrlKey || event.shiftKey || event.altKey || event.which === 2) {
142				return;
143			}
144			event.preventDefault();
145			postToParent('navigate', { pathAndQuery: $(this).attr('data-embedded-nav-path') });
146		});
147	}
148
149	window.addEventListener('message', function (event) {
150		if (!canPostToParent || event.origin !== settings.parentOrigin || event.source !== window.parent) {
151			return;
152		}
153		var data = event.data || {};
154		if (data.source !== settings.hostSource || !data.type) {
155			return;
156		}
157		if (data.type === 'height-request') {
158			scheduleHeightPost();
159			return;
160		}
161		if (settings.rewriteInternalLinks && data.type === 'navigate' && data.payload && data.payload.pathAndQuery) {
162			var safePath = resolveInternalHref(data.payload.pathAndQuery);
163			if (safePath) {
164				window.location.assign(safePath);
165			}
166		}
167	});
168
169	// Expose a helper so programmatic (non-anchor) navigations can drive the
170	// parent Create page instead of navigating inside the embedded iframe.
171	// Returns true when the navigate message was posted to the parent.
172	window.classicEmbeddedNavigate = function (pathAndQuery) {
173		if (!canPostToParent || !pathAndQuery) {
174			return false;
175		}
176		// Fail closed: only ever ask the parent to navigate to a same-origin path,
177		// matching the sanitization used for anchors and inbound navigate messages.
178		var safePath = resolveInternalHref(pathAndQuery);
179		if (!safePath) {
180			return false;
181		}
182		postToParent('navigate', { pathAndQuery: safePath });
183		return true;
184	};
185
186	$(document).ready(function () {
187		scheduleRewriteInternalLinks();
188		scheduleHeightPost();
189		window.setTimeout(scheduleHeightPost, 150);
190		window.setTimeout(scheduleHeightPost, 450);
191	});
192
193	$(window).on('load resize', scheduleHeightPost);
194	if (settings.observeMutations && typeof MutationObserver !== 'undefined') {
195		new MutationObserver(function () {
196			scheduleRewriteInternalLinks();
197			scheduleHeightPost();
198		}).observe(document.body, {
199			childList: true,
200			subtree: true,
201			attributes: true
202		});
203	}
204}
205
206$(document).ready(function () {
207	if (!readCookie('s'))
208		createCookie('s', getGUID());
209
210	$('div#tabs ul.menu li ul').addClass('subnav');
211	$('div#tabs ul.menu li a').mouseover(function () {
212		$(this).parent().find('ul.subnav').slideDown('fast').show();
213		$(this).parent().hover(function () { }, function () {
214			$(this).parent().find('ul.subnav').slideUp('slow');
215		});
216	}).hover(function () {
217		$(this).addClass('subhover');
218	}, function () {
219		$(this).removeClass('subhover');
220	});
221	if ($('.err404').length === 0) logView();
222	initStats();
223	selectTab();
224
225	$(window).on('hashchange', function () {
226		if (window.location.hash === '#body') {
227			skipToMainContent(window.location.hash);
228		}
229	});
230
231	$('.emailform').each(function () {
232		var $form = $(this);
233		$form.on('submit', function (event) {
234			event.preventDefault();
235			ok = true;
236			$('.required input, .required select, .required textarea', $form).each(function (index, field) {
237				if ($(field).val().length === 0) {
238					ok = false;
239					$(field).closest('.form-group').addClass('has-error has-feedback').delay(3000).queue(function () {
240						$(this).removeClass("has-error has-feedback").dequeue();
241					});
242					$form.parent().find('.error').text('Missing required fields').show().delay(3000).fadeOut();
243				}
244			});
245			if (ok) {
246				$.ajax({
247					type: "POST",
248					url: $form.attr('action'),
249					data: $form.serialize(),
250					success: function (data) {
251						if (data.status === 'error') {
252							if (typeof Recaptcha !== 'undefined' && Recaptcha.reload) {
253								Recaptcha.reload();
254							}
255							$form.parent().find('.error').text(data.message).show().delay(3000).fadeOut();
256						} else {
257							$form.parent().find('.message').show();
258							$form[0].reset();
259						}
260					}
261				});
262			}
263			return false;
264		});
265	});
266	$('div#body.mobile .widgetheader').on('click', function (event) {
267		event.preventDefault();
268		if ($(window).width() <= 768) {
269			if ($(this).closest('.widget').hasClass('open')) {
270				$(this).closest('.widget').removeClass('open');
271			} else {
272				$('.widget.open').removeClass('open');
273				$(this).closest('.widget').toggleClass('open');
274			}
275		}
276	});
277	initSideloadLinks();
278
279	// Handling for credit card transaction returns. PayPal PayFlow.
280	$(window).on('message onmessage', function (e) {
281		var data = e.originalEvent.data;
282		if (typeof data.type !== 'undefined') {
283			if (data.type === 'attend') {
284				if (typeof data.ok !== 'undefined' && typeof data.regCache !== 'undefined') {
285					completeEventTransaction(data.ok, data.regCache);
286				}
287			}
288
289			if (data.type === 'reserve') {
290				if (typeof data.ok !== 'undefined' && typeof data.bookings !== 'undefined' && typeof data.transactionData !== 'undefined') {
291					completeRoomTransaction(data.ok, data.bookings, data.transactionData);
292				}
293			}
294		}
295	});
296
297	$(window).on('resize', function () {
298		$('.popupwidget').each(function (index, el) {
299			$(this).position({
300				of: $(window)
301			});
302			$(this).css('top', $(window).scrollTop() + 'px');
303		});
304
305		$('.temp_mask').css({
306			height: $(document).height(),
307			width: $(document).width()
308		});
309		resizeDates();
310	});
311
312	try {
313		init();
314	} catch (e) {
315		if (console) console.log('init error', e);
316	}
317
318	if (window.classicEmbeddedPageConfig) {
319		initClassicEmbeddedPage(window.classicEmbeddedPageConfig);
320	}
321
322});
323navigator.sayswho = (function () {
324	var data = {};
325	var ua = navigator.userAgent,
326		tem,
327		M = ua.match(/(opera|chrome|safari|firefox|msie|trident|adobeair|mobile(?=\/))\/?\s*([\d\.]+)/i) || [];
328	if (/trident/i.test(M[1])) {
329		tem = /\brv[ :]+(\d+(\.\d+)?)/g.exec(ua) || [];
330		data.n = 'MSIE';
331		data.v = tem[1] || '';
332	} else {
333		M = M[2] ? [M[1], M[2]] : [navigator.appName, navigator.appVersion, '-?'];
334		//        if((tem= ua.match(/version\/([\.\d]+)/i))!= null) M[2]= tem[1];
335		data.n = M[0];
336		data.v = M[1];
337	}
338
339	if (navigator.appVersion.indexOf("Win") != -1) data.o = "Windows";
340	if (navigator.appVersion.indexOf("Mac") != -1) data.o = "MacOS";
341	if (navigator.appVersion.indexOf("X11") != -1) data.o = "UNIX";
342	if (navigator.appVersion.indexOf("Linux") != -1) data.o = "Linux";
343
344	return data;
345})();
346
347function getWidgetContent(id, loc) {
348	var ret = "";
349	var l = "";
350	if (loc && loc.length > 0) {
351		l = '&location=' + loc;
352	}
353	$.ajax({
354		url: '/widget?contentonly=yes&id=' + id + l,
355		success: function (html) {
356			ret = html;
357		},
358		async: false
359	});
360	return ret;
361}
362
363function getGUID() {
364	return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) {
365		var r = Math.random() * 16 | 0,
366			v = c == 'x' ? r : (r & 0x3 | 0x8);
367		return v.toString(16);
368	});
369}
370function initRegButtons() {
371	$('.registerForEvent').regButton();
372}
373function init() {
374	var menuTimer = false;
375	$('ul.dropdown-menu').on('mouseleave', function (event) {
376		event.preventDefault();
377		menuTimer = setTimeout(function () {
378			$('.dropdown.open').removeClass('open');
379			$(":focus").blur();
380		}, 500);
381	}).on('mouseenter', function (event) {
382		event.preventDefault();
383		if (menuTimer) clearTimeout(menuTimer);
384	});
385
386	$('.font-down').on('click', function (event) {
387		event.preventDefault();
388		var newSize = parseInt($('body').css('font-size'), 10) - 1;
389		if (newSize >= $(this).data('base-size')) {
390			$('body').css('font-size', newSize + 'px');
391		}
392	}).data('base-size', parseInt($('body').css('font-size')));
393
394	$('.font-up').on('click', function (event) {
395		event.preventDefault();
396		var newSize = parseInt($('body').css('font-size'), 10) + 1;
397		if (newSize < 30) {
398			$('body').css('font-size', newSize + 'px');
399		}
400	});
401
402	// $('.dynamic-widget').each(function() {
403	//     $(this).html(getWidgetContent($(this).attr('data-fill-with'), $(this).attr('data-location')));
404	// });
405	var toggleFaqAnswer = function (event) {
406	if (event.type === 'keypress') {
407		var key = typeof event.key === 'string' ? event.key : null;
408		if (key) {
409			if (key !== 'Enter' && key !== ' ' && key !== 'Spacebar') {
410				return;
411			}
412		} else {
413			var code = event.which || event.keyCode;
414			if (code !== 13 && code !== 32) {
415				return;
416			}
417		}
418	}
419		event.preventDefault();
420		var $question = $(this);
421		if ($question.parent().find('.amfaq-section-answer-selected').length > 0) {
422			$('.amfaq-section-answer-selected').removeClass('amfaq-section-answer-selected');
423		} else {
424			$('.amfaq-section-answer-selected').removeClass('amfaq-section-answer-selected');
425			$question.parent().find('.amfaq-section-answer').addClass('amfaq-section-answer-selected');
426		}
427	};
428	$('.amfaq-section-question').on('click', toggleFaqAnswer);
429	$('.amfaq-section-question').on('keypress', toggleFaqAnswer);
430	$('[data-link]').each(function (index, el) {
431		var url = decodeURIComponent($(el).attr('data-link'));
432		$(this).on('click', function (event) {
433			event.preventDefault();
434			if (url.indexOf('http://') === 0 || url.indexOf('https://') === 0) {
435				window.open(url, '_blank');
436			} else {
437				window.open(url, '_top');
438			}
439		}).css('cursor', 'pointer');
440	});
441	$('[data-broadcast-show]').each(function (index, el) {
442		var apiserver = $('meta[name=apiserver]').attr('content') || 'https://api.communico.co';
443		$.getJSON(apiserver + '/v1/broadcasts/show/' + $(el).attr('data-broadcast-show'), function (json, textStatus) {
444			$(el).amShow({ scenes: json });
445		});
446	});
447	$('[data-tile-url]').each(function (index, el) {
448		var url = decodeURIComponent($(this).attr('data-tile-url'));
449		var pat = /^https?:\/\//i;
450		if (pat.test(url)) {
451			$(this).wrap('<a target="_blank" href="' + url + '"></a>');
452		} else {
453			$(this).wrap('<a target="_top" href="' + url + '"></a>');
454		}
455	});
456	// $('[data-tile-url]').on('click', function(event) {
457	// 	event.preventDefault();
458	// 	var url = decodeURIComponent($(this).attr('data-tile-url'));
459	// 	var pat = /^https?:\/\//i;
460	// 	if (pat.test(url)){
461	// 		window.open(url, '_blank');
462	// 	}else{
463	// 		window.open(url, '_top');
464	// 	}
465	// });
466	$('.amsb-tabs>li').on('click', function (event) {
467		event.preventDefault();
468		$(this).closest('.amsb-tabs').find('.amsb-tab-active').removeClass('amsb-tab-active');
469		var c = $(this).attr('class');
470		$(this).addClass('amsb-tab-active');
471		$(this).closest('.amsb-tabs').parent().find('.amsb-tab-content').hide();
472		$(this).closest('.amsb-tabs').parent().find('.' + c + '-content').show();
473
474	});
475	$('.amsc-tabs>li').on('click', function (event) {
476		event.preventDefault();
477		$(this).closest('.amsc-tabs').find('.amsc-tab-active').removeClass('amsc-tab-active');
478		var c = $(this).attr('class');
479		$(this).addClass('amsc-tab-active');
480		$(this).closest('.amsc-tabs').parent().find('.amsc-tab-content').hide();
481		$(this).closest('.amsc-tabs').parent().find('.' + c + '-content').show();
482
483	});
484	setTimeout(function () {
485		$('.ame-events-slideshow').cycle().on('cycle-after', function (event, optionHash, outgoingSlideEl, incomingSlideEl, forwardFlag) {
486			$(".ame-events-slideshow-desc", incomingSlideEl).trigger("update");
487		}).on('cycle-initialized', function (event) {
488		});
489		$(".ame-events-slideshow .ame-events-slideshow-desc").dotdotdot({
490			callback: function (isTruncated, orgContent) {
491				//			console.log(isTruncated, orgContent);
492			}
493		});
494
495	}, 500);
496
497	$('.amh-tile').on('mouseover', function (event) {
498		event.preventDefault();
499		// $(this).css('max-height', $(this).outerHeight());
500		$(this).addClass('amh-hover-state');
501	}).on('mouseout', function (event) {
502		event.preventDefault();
503		$(this).removeClass('amh-hover-state');
504		// $(this).css('max-height', '');
505
506	});
507	$('.amev-cal').amEVWidget();
508
509	$('.amev-event-list').on('click', '.amev-show-full', function (event) {
510		event.preventDefault();
511		var $desc = $(this).closest('.amev-event-description');
512		$desc.find('.amev-event-description-truncated').hide();
513		$desc.find('.amev-event-description-full').show();
514	});
515
516	$('.recreads-list').amRecReads();
517	$('.ambl-list').amBookList();
518	$('.amsre-list').amSierraRecReads();
519	$('.amsire-list').amSirsiRecReads();
520	$('.circulation_wrapper').amCirculation();
521	$('.regbtn').each(function () {
522		if (!$(this).data('reg')) {
523			$(this).data('reg', true);
524			var event_id = $(this).data('eventid');
525			var location_id = $(this).data('locationid');
526			var regstatus = parseInt($(this).data('total_registrants'), 10) >= parseInt($(this).data('max_attendee'), 10) ? '0' : '1';
527
528			$(this).on('click', function () {
529				var $data = $('<div class="eventregform"></div>');
530				$data.append($('.eelisttitle', $(this).closest('.eelistevent')).clone());
531				$data.append($('.eelisttime', $(this).closest('.eelistevent')).clone());
532				$data.append($('.eelistgroup', $(this).closest('.eelistevent')).clone());
533				$data.append($('.eelisttags', $(this).closest('.eelistevent')).clone());
534				$data.append($('.eelistdesc', $(this).closest('.eelistevent')).clone());
535
536				var $form = $('<div class="popupform"></div>');
537				$data.append($form);
538				$form.append(formPair('name', 'Name'));
539				$form.append(formPair('tel', 'Telephone'));
540				$form.append(formPair('email', 'Email'));
541
542				$form.append($('<div class="button eventRegButton">Submit</div>').on('click', function () {
543					var btn = this;
544					$('.formerr', $form).remove();
545					var ok = true;
546					if ($('#name', $form).val().length === 0) {
547						$('#name', $form).parent().append('<div class="formerr">Name is required</div>');
548						ok = false;
549					}
550					if ($('#tel', $form).val().length === 0 && $('#email', $form).val().length === 0) {
551						$('#email', $form).parent().append('<div class="formerr">A telephone number or email address is required</div>');
552						ok = false;
553					}
554
555					if (ok) {
556						$.post('/eeventcaldata', {
557							name: $('#name', $form).val(),
558							tel: $('#tel', $form).val(),
559							email: $('#email', $form).val(),
560							event_id: event_id,
561							status: regstatus,
562							location_id: location_id
563						}, function (data, textStatus, xhr) {
564							$('.popupwidgetclose').trigger('click');
565						});
566					}
567				}));
568
569				$popupwidget = showPopupWidget('Register for event', $data);
570				$popupwidget.css('width', '460px');
571				$popupwidget.position({
572					of: $(window)
573				});
574			});
575		}
576	});
577
578	$('.accordion').each(function () {
579		if (!$(this).attr('done')) {
580			$(this).attr('done', true);
581			initAccordion('#' + $(this).attr('id'));
582			$(this).find('[open=yes]').trigger('click');
583		}
584	});
585	$('.rsswidget').each(function () {
586		if (!$(this).attr('done')) {
587			$(this).attr('done', true);
588			iniRSSWidgets('#' + $(this).attr('id'));
589		}
590	});
591
592	if ($('.librarycard-form').length > 0) {
593		initLibraryCardForm();
594	}
595
596	initToggles();
597	iniResItems();
598	initButtonWidgets();
599	initPopupLinks();
600	initBookmarkItems();
601	initeEventPopupLinks();
602	initOpeningHoursTables();
603	initRegButtons();
604	try {
605		initTwitter();
606		initVideo();
607	} catch (e) { }
608	initFlickr();
609	initSlideShows();
610	initSearchBoxes();
611	initNYPLCollections();
612
613	$('.advanced-slideshow-widget').amAdvancedSlideshow();
614
615	$('.eeventmoreless').click(function () {
616		var $desc = $(this).parent().children('.eeventdesc');
617		if ($desc.is(':hidden')) {
618			$(this).text('Close');
619			$desc.fadeIn();
620		} else {
621			$(this).text('More info');
622			$desc.fadeOut();
623		}
624	});
625
626	$('.date').each(function () {
627		var $box = $(this);
628		$box.html(getDateTime());
629		setInterval(function () {
630			$box.html(getDateTime());
631		}, 1000);
632	});
633
634	if ($('.subscribeToEvent').length > 0) {
635		$('.subscribeToEvent').on('click', function () {
636			showInterestedPopup($(this).attr('data-eventid'), $(this).attr('data-recurringid'), {
637				'title': $(this).attr('data-event-title') + ' - ' + $(this).attr('data-event-subtitle'),
638				'datestring': $(this).attr('data-event-datestring') + ' - ' + $(this).attr('data-event-timestring'),
639				'location': $(this).attr('data-event-location')
640			});
641		});
642	}
643}
644
645function showInterestedPopup(dateId, recurringId, event) {
646	var self = this;
647	var eventInfo = {
648		title: event.title,
649		datestring: event.datestring,
650		location: event.location
651	};
652
653	var interested = new EventBillingSubscriptions(dateId, recurringId, eventInfo, false);
654	var interestedForm = interested.subscriptionForm;
655	interestedForm.appendTo('body');
656	$('.Event_Full-dialog').modal({
657		backdrop: 'static',
658		keyboard: false
659	}).modal('show');
660}
661
662function addSearch() {
663	if (window.external && ('AddSearchProvider' in window.external)) {
664		if (!window.location.origin) {
665			window.location.origin = window.location.protocol + "//" + window.location.hostname + (window.location.port ? ':' + window.location.port : '');
666		}
667		window.external.AddSearchProvider(window.location.origin + "/opensearch.xml");
668	}
669}
670
671function logView() {
672	try {
673		var data = {};
674		data.p = $('[data-pageid]').attr('data-pageid');
675		data.c = $('meta[name=client]').attr('content');
676		data.u = window.location.href.split('?')[0].toString().split(window.location.host)[1];
677		logStat('view', data);
678	} catch (e) { }
679}
680
681function initStats() {
682	$(document.body).on('click', function (e) {
683		try {
684			if (typeof e.pageX === "undefined" || typeof e.pageY === "undefined") return true; //no click info so bail
685			var pid = $('[data-pageid]').attr('data-pageid');
686			if (typeof pid === "undefined" || pid.length === 0) return true;
687			var data = {};
688			data.p = pid;
689			data.x = e.pageX;
690			data.y = e.pageY;
691			data.s = $(document).width();
692			data.c = $('meta[name=client]').attr('content');
693			data.u = window.location.href.split('?')[0].toString().split(window.location.host)[1];
694			var w = $(e.target).closest('.widget').attr('id');
695			if (w) data.w = w;
696			logStat('click', data);
697		} catch (e) { }
698		return true;
699	});
700	$(document.body).on('click', 'a', function (e) {
701		try {
702			var pid = $('[data-pageid]').attr('data-pageid');
703			if (typeof pid === "undefined" || pid.length === 0) return true;
704			var data = {};
705			data.p = pid;
706			data.l = $(this).attr('href');
707			var text = $(this).text();
708			if (text.length > 0) data.t = text;
709			data.c = $('meta[name=client]').attr('content');
710			data.u = window.location.href.split('?')[0].toString().split(window.location.host)[1];
711			var w = $(e.target).closest('.widget').attr('id');
712			if (w) data.w = w;
713			logStat('link', data);
714			return true;
715		} catch (e) { }
716		return true;
717	});
718}
719
720function resizeDates() {
721	$('.eecallistheaderdate p').each(function () {
722		var d = $('#datepicker', $(this).closest('.widgetbody')).datepicker('getDate');
723		$(this).text(getSizedDate(d));
724	});
725}
726
727function getSizedDate(d) {
728	if ($(window).width() >= 1024) {
729		return moment(d).format('ddd, MMM Do YYYY');
730	} else if ($(window).width() >= 768) {
731		return moment(d).format('ddd, MMM Do YYYY');
732	} else if ($(window).width() >= 480) {
733		return moment(d).format('MMM Do YY');
734	} else {
735		return moment(d).format('MMM YYYY');
736	}
737}
738
739function initSearchBoxes() {
740	$('.wsearchbox input').keypress(function (e) {
741		if (e.which == 13) {
742			$('.wsearchbutton button', $(this).closest('.searchwidget')).trigger('click');
743		}
744	});
745
746	$('.wsearchbutton button').on('click', function () {
747		var term = $('.wsearchbox input', $(this).closest('.searchwidget')).val();
748		if (term.length === 0) return;
749
750		var url = decodeURIComponent($(this).attr('data-url'));
751		window.open(url.replace(/{.*}/, term), '_blank');
752	});
753}
754
755function selectTab() {
756	var pageid = $('[data-pageid]').data('pageid');
757
758	$('.current').removeClass('current');
759	$('.navbar-top .navbar-nav a').each(function (index, el) {
760		var href = $(this).attr("href");
761		if (href) {
762			var id = href.substr(href.lastIndexOf('/') + 1).replace(/^\D+/g, '');
763			if (parseInt(id, 10) === parseInt(pageid, 10)) {
764				$(this).addClass('current');
765				$(this).closest('.dropdown').find('.dropdown-toggle').addClass('current');
766			} else if (window.location.pathname == href) {
767				$(this).addClass('current');
768				$(this).closest('.dropdown').find('.dropdown-toggle').addClass('current');
769			}
770		}
771	});
772	if ($('.current').length === 0) {
773		$('.navbar-top .navbar-nav a:first()').addClass('current');
774	}
775
776	var parts = window.location.pathname.split('/');
777	var portal = $('[data-portal]').attr('data-portal');
778	var index = portal && portal.length > 0 && portal == parts[1] ? 2 : 1;
779	var p = parts[index];
780	if (p) {
781		$('.tab').each(function () {
782			var $tab = $(this);
783			if ($(this).attr('href').split('/')[index] === p) {
784				$tab.addClass('tab_selected');
785			} else {
786				$tab.removeClass('tab_selected');
787			}
788		});
789	} else {
790		$('.tab:first').addClass('tab_selected');
791	}
792}
793
794function initSideloadLinks() {
795	if (typeof history.pushState !== "undefined") {
796		$('.sideload_fade').on('click', function () {
797			var pages = [];
798			$('.sideload_fade').each(function () {
799				pages.push($(this).attr('href').split('/')[1]);
800			});
801			var o = pages.indexOf(window.location.pathname.split('/')[1]);
802			var n = pages.indexOf($(this).attr('href').split('/')[1]);
803			history.pushState({
804				state: 1
805			}, $(this).text(), $(this).attr('href'));
806			document.title = $(this).text();
807			selectTab();
808			$.ajax({
809				url: $(this).attr('href') + '?sideload=1',
810				success: function (data) {
811					$('#body').fadeOut(100, function () {
812						$(this).html(data).fadeIn(100, function () {
813							logView();
814							init();
815						});
816					});
817				}
818			});
819			return false;
820		});
821
822		$('.sideload_slide').on('click', function () {
823			var pages = [];
824			$('.sideload_slide').each(function () {
825				pages.push($(this).attr('href').split('/')[1]);
826			});
827			var o = pages.indexOf(window.location.pathname.split('/')[1]);
828			var n = pages.indexOf($(this).attr('href').split('/')[1]);
829			history.pushState({
830				state: 1
831			}, $(this).text(), $(this).attr('href'));
832			document.title = $(this).text();
833			selectTab();
834			$.ajax({
835				url: $(this).attr('href') + '?sideload=1',
836				success: function (data) {
837					var width = $('#body').width();
838					if (o > n) {
839						$('#body').parent().append('<div id="newbody"></div>');
840						$("#newbody").hide().html(data);
841
842						$("#body").hide("slide", {
843							direction: "right"
844						}, 500, function () {
845							$(this).remove();
846						});
847						$("#newbody").show("slide", {
848							direction: "left"
849						}, 500).attr('id', 'body');
850					} else if (o < n) {
851						$('#body').parent().append('<div id="newbody"></div>');
852						$("#newbody").hide().html(data);
853
854
855						$("#newbody").show("slide", {
856							direction: "right"
857						}, 500).attr('id', 'body');
858						$("#body").hide("slide", {
859							direction: "left"
860						}, 500, function () {
861							$(this).remove();
862						});
863
864					} else {
865						$('#body').fadeOut(100, function () {
866							$(this).html(data).fadeIn(100, function () {
867								logView();
868								init();
869							});
870						});
871					}
872				}
873			});
874			return false;
875		});
876	}
877}
878
879function initSlideShows() {
880	$('.slidelist img').each(function (idx, img) {
881		$(img).css('width', $(img).closest('.slideshowwidget').width() + 'px');
882	});
883	$('.slidelist').cycle();
884}
885
886function initFlickr() {
887	$('.flikr_widget').each(function () {
888		$(this).hide();
889		var hid = 'flickr_holder_' + $(this).attr('id');
890		$holder = $('<div ="flickr_over"></div>');
891		$(this).parent().prepend($holder);
892		$holder.append('<img src="/images/common/flikr/flickr.png">');
893		$enlarge = $('<i class="icon-zoom-in icon-2x"></i><img src="/images/common/flikr/flickr-e.png">');
894		$enlarge.css('cursor', 'pointer');
895		$enlarge.css('float', 'right');
896		$enlarge.on('click', function () {
897			flickrEnlarge(hid);
898		});
899		$holder.append($enlarge);
900		$holder.append($('<div id="' + hid + '" class="flickr_holder"></div>'));
901
902		$controls = $('<div class="flickr_controls"></div>');
903		$holder.append($controls);
904
905		$back = $('<i class="icon-backward icon-2x"></i>');
906		$back.on('click', function () {
907			flickrPrev(hid);
908		});
909
910
911		$fwd = $('<i class="icon-forward icon-2x"></i>');
912		$fwd.on('click', function () {
913			flickrNext(hid);
914		});
915
916
917		$pause = $('<i class="icon-pause icon-2x"></i>');
918		$pause.on('click', function () {
919			flickrPauseToggle(hid);
920			if ($(this).hasClass('icon-pause')) {
921				$(this).removeClass('icon-pause').addClass('icon-youtube-play');
922			} else {
923				$(this).addClass('icon-pause').removeClass('icon-youtube-play');
924			}
925		});
926
927
928		$controls.append($back).append($pause).append($fwd);
929
930		var flickr_list = [];
931		$('li', this).each(function () {
932			var itm = {};
933			itm.url = $(this).text();
934			itm.large = $(this).attr('data-large');
935			itm.small = $(this).attr('data-small');
936			itm.title = $(this).attr('data-title');
937			itm.desc = $(this).attr('data-desc');
938			flickr_list.push(itm);
939		});
940
941		flickrShow(flickr_list, hid);
942	});
943}
944
945function getLocation() {
946	if ($('meta[name=location]').length > 0) {
947		return $('meta[name=location]').attr('content');
948	}
949	var input = window.location.href;
950	if (!input) return false;
951	var parts = input.split('/');
952	for (var i = 0; i < parts.length; i++) {
953		if (parts[i] == 'location') return parts[i + 1];
954	}
955	return false;
956}
957
958function initOpeningHoursTables() {
959	var location = getLocation();
960	if (!location) return;
961	$('.openingtimes').each(function () {
962		var $p = $(this);
963		var location_id = $p.attr("id");
964		if (!$p.attr('week')) $p.attr('week', 0);
965		var bindControl = function (selector, updater) {
966			var $control = $p.find(selector);
967			var handler = function (event) {
968				if (event.type === 'keypress') {
969					var code = event.which || event.keyCode;
970					if (code !== 13 && code !== 32) {
971						return;
972					}
973				}
974				event.preventDefault();
975				var l = $(this).attr('data-location-keyword') || location;
976				updater(l);
977			};
978			$control.on('click', handler);
979			$control.on('keypress', handler);
980		};
981		bindControl('.prev_openingtimes', function (l) {
982			if ($p.attr('week') > 0) $p.attr('week', parseInt($p.attr('week'), 10) - 1);
983			updateOpeningHours($p, l, location_id);
984		});
985		bindControl('.curr_openingtimes', function (l) {
986			$p.attr('week', 0);
987			updateOpeningHours($p, l, location_id);
988		});
989		bindControl('.next_openingtimes', function (l) {
990			$p.attr('week', parseInt($p.attr('week'), 10) + 1);
991			updateOpeningHours($p, l, location_id);
992		});
993	});
994}
995
996function updateOpeningHours($target, location, location_id) {
997	$.get('/openingtimes/location/' + location + '?week=' + $target.attr('week'), function (data) {
998		// Fix from above, continued. Using ID get correct table and replace HTML.
999		var newel = $target.data("new-element");
1000		data = data.replace(/(\r\n\t|\n|\r\t)/gm, "");
1001		if (newel) {
1002			newel.children('.openingtimes_table').empty().append(data);
1003		} else {
1004			$('#' + location_id).children(".openingtimes_table").html(data);
1005		}
1006	});
1007}
1008function getSearchResults(ils, term, start) {
1009	var client = $('meta[name=client]').attr('content');
1010	var apiserver = $('meta[name=apiserver]').attr('content') || 'https://api.communico.co';
1011
1012	var results = { start: start, limit: 3, total: 0, term: term, entries: [] };
1013
1014	return new Promise(function (resolve, reject) {
1015		switch (ils) {
1016			case 'polaris':
1017				$.getJSON(apiserver + '/v1/' + client + '/polaris/search/', { q: term, page: (start / results.limit) + 1, bibsperpage: results.limit, keyword: 'KW', sortby: 'RELEVANCE', limit: 'TOM=*' }, function (json, textStatus) {
1018					results.total = json.data.TotalRecordsFound;
1019					$.each(json.data.BibSearchRows, function (index, result) {
1020						var server = index % 10;
1021						var coverUrl = 'https://covers' + server + '.communico.co/' + client + '/cover/?';
1022
1023						if (result.ISBN) {
1024							coverUrl += 'type=isbn&id=' + result.ISBN.replace(/[^\dx]/g, '') + '&';
1025						} else if (result.UPC) {
1026							coverUrl += 'type=upc&id=' + result.UPC.replace(/[^\dx]/g, '') + '&';
1027						} else if (result.OCLC) {
1028							coverUrl += 'type=oclc&id=' + result.OCLC.replace(/[^\dx]/g, '') + '&';
1029						}
1030
1031						coverUrl += 'title=' + encodeURIComponent(result.Title || "No Cover Image Available");
1032
1033						results.entries.push({
1034							id: result.ControlNumber,
1035							title: result.Title,
1036							author: result.Author,
1037							year: result.PublicationDate,
1038							image: coverUrl
1039						});
1040					});
1041					resolve(results);
1042				});
1043				break;
1044			case 'iii':
1045				$.getJSON(apiserver + '/v2/' + client + '/sierra/search?type=Rightresultfull&start=' + start + '&limit=' + results.limit + '&q=' + term, function (json, textStatus) {
1046					results.total = json.data.total;
1047					$.each(json.data.entries, function (index, result) {
1048
1049						var server = index % 10;
1050						var coverUrl = 'https://covers' + server + '.communico.co/' + client + '/cover/?';
1051
1052						if (result.upcs[0]) {
1053							coverUrl += 'type=upc&id=' + result.upcs[0] + '&';
1054						} else if (result.isbns[0]) {
1055							coverUrl += 'type=isbn&id=' + result.isbns[0] + '&';
1056						}
1057
1058						coverUrl += 'title=' + encodeURIComponent(result.title || "No Cover Image Available");
1059
1060						results.entries.push({
1061							id: result.id,
1062							title: result.title,
1063							author: result.author,
1064							year: result.publishYear + '',
1065							image: coverUrl
1066						});
1067					});
1068					resolve(results);
1069				});
1070
1071				break;
1072			default:
1073				reject('unknown ILS');
1074				break;
1075		}
1076	});
1077}
1078function initToggles() {
1079	$('[id^=toggle_]').each(function () {
1080		if ($(this).data('toggle')) return;
1081		$(this).data('toggle', true);
1082		var targetid = $(this).attr('id').substring(7);
1083		$(this).css('cursor', 'pointer');
1084		$(this).click(function () {
1085			$('#' + targetid).fadeToggle();
1086		});
1087	});
1088	$('[id^=togglepopup_]').each(function () {
1089		if ($(this).data('toggle')) return;
1090		$(this).data('toggle', true);
1091		var title = $(this).data('title');
1092		var max = $(this).data('max');
1093		var targetid = $(this).attr('id').substring(12);
1094		$(this).css('cursor', 'pointer');
1095		$(this).click(function () {
1096			var t = $('#' + targetid);
1097			var tc = t.clone(true).show();
1098			t.data("new-element", tc);
1099
1100			var $popupwidget = showPopupWidget(title, tc, null);
1101			$popupwidget.css('max-width', max);
1102			$popupwidget.position({
1103				of: $(window)
1104			});
1105		});
1106	});
1107	$('[id^=mappopup_]').each(function () {
1108		if ($(this).data('toggle')) return;
1109		$(this).data('toggle', true);
1110		var title = $(this).data('title');
1111		var max = $(this).data('max');
1112		var lat = $(this).data('lat');
1113		var lon = $(this).data('lon');
1114
1115		$(this).css('cursor', 'pointer');
1116		$(this).click(function () {
1117			var $data = $('<iframe width="100%" height="400" frameborder="0" style="border:0" src="https://www.google.com/maps/embed/v1/place?q=' + lat + ',' + lon + '&key=AIzaSyBIswHRc1E1cJ0rOY7JpZIo-KPCh9OMgJY"></iframe>');
1118			var $popupwidget = showPopupWidget(title, $data);
1119			$popupwidget.css('max-width', max);
1120			$popupwidget.position({
1121				of: $(window)
1122			});
1123		});
1124	});
1125
1126
1127}
1128
1129function getDateTime() {
1130	var bits = moment().format('LLLL').split(' ');
1131	return bits[0] + ' ' + bits[2] + ' ' + bits[1] + ' ' + bits[3] + ' <b>' + bits[4] + '' + bits[5] + '</b>';
1132}
1133
1134function initBookmarkItems() {
1135	$('.bookmark_list').each(function () {
1136		var $tabList = $(this);
1137		var style = $tabList.attr('viewstyle');
1138		var $bookmarkBody = $('<div class="bookmark_body toprule"/>');
1139		$tabList.after($bookmarkBody);
1140		var $tabs = $tabList.children('li');
1141		$tabs.each(function () {
1142			var $tab = $(this);
1143			$tab.attr('role', 'presentation').addClass('widget_tab');
1144			var $header = $tab.children('.bookmark_section_header');
1145			var $panel = $tab.children('ul').first();
1146			if ($panel.length === 0) return;
1147			$panel.hide();
1148			$panel.addClass('bookmark_item_list').attr('aria-hidden', 'true').attr('hidden', 'hidden');
1149			if (style == 1) {
1150				var pageid = $('[data-pageid]').data('pageid');
1151				$panel.children('li').addClass('button-strip');
1152				$panel.find('a').each(function () {
1153					var href = $(this).attr('href');
1154					if (href) {
1155						var id = href.substr(href.lastIndexOf('/') + 1).replace(/^\D+/g, '');
1156						if (parseInt(id, 10) === parseInt(pageid, 10)) {
1157							$(this).parent().addClass('button-strip-active');
1158						}
1159					}
1160				});
1161			} else {
1162				$panel.children('li').addClass('bottomrule');
1163			}
1164			$bookmarkBody.append($panel);
1165		});
1166
1167		var $headers = $tabList.find('.bookmark_section_header');
1168		var $panels = $bookmarkBody.children('ul');
1169
1170		var activateTab = function ($header, focus) {
1171			if (!$header || !$header.length) return;
1172			var panelId = $header.attr('aria-controls');
1173			var $panel = panelId ? $('#' + panelId) : $();
1174			$tabs.removeClass('widget_tab_selected');
1175			$panels.hide().attr('aria-hidden', 'true').attr('hidden', 'hidden');
1176			$headers.attr('aria-selected', 'false').attr('tabindex', '-1');
1177			if ($panel.length) {
1178				$panel.show().attr('aria-hidden', 'false').removeAttr('hidden');
1179			}
1180			$header.attr('aria-selected', 'true').attr('tabindex', '0');
1181			$header.closest('li').addClass('widget_tab_selected');
1182			if (focus) {
1183				$header.focus();
1184			}
1185		};
1186
1187		var focusByOffset = function ($current, offset) {
1188			var currentIndex = $headers.index($current);
1189			if (currentIndex === -1) return;
1190			var targetIndex = (currentIndex + offset + $headers.length) % $headers.length;
1191			var $target = $headers.eq(targetIndex);
1192			activateTab($target, true);
1193		};
1194
1195		$headers.each(function () {
1196			var $header = $(this);
1197			$header.on('click', function (event) {
1198				event.preventDefault();
1199				activateTab($header, false);
1200			});
1201			$header.on('keydown', function (event) {
1202				var key = event.which || event.keyCode;
1203				switch (key) {
1204					case 13: // Enter
1205					case 32: // Space
1206						event.preventDefault();
1207						activateTab($header, false);
1208						break;
1209					case 37: // Left
1210					case 38: // Up
1211						event.preventDefault();
1212						focusByOffset($header, -1);
1213						break;
1214					case 39: // Right
1215					case 40: // Down
1216						event.preventDefault();
1217						focusByOffset($header, 1);
1218						break;
1219					default:
1220						break;
1221				}
1222			});
1223		});
1224
1225		if ($headers.length) {
1226			activateTab($headers.first(), false);
1227		}
1228
1229		if ($headers.length === 1) {
1230			$tabList.attr('aria-hidden', 'true').hide();
1231			$bookmarkBody.css('padding-top', 0);
1232		}
1233	});
1234}
1235
1236function setStyleSheet(url) {
1237	var $contrastSheet = $('#contrastsheet');
1238
1239	if (!url) {
1240		$contrastSheet.remove();
1241		return;
1242	}
1243
1244	if ($contrastSheet.length === 0) {
1245		$contrastSheet = $('<link>', {
1246			id: 'contrastsheet',
1247			rel: 'stylesheet',
1248			type: 'text/css'
1249		}).appendTo('head');
1250	}
1251
1252	$contrastSheet.attr('href', url);
1253}
1254
1255function setFontSize(size) {
1256	document.body.style.fontSize = size;
1257}
1258
1259function openAccessibility() {
1260	$('#accessibility').slideToggle();
1261	return false;
1262}
1263
1264function eEventPopup(link) {
1265	var $me = $(link);
1266	var event_type = $me.attr('data-type');
1267	$.get('/eeventcal?event_type=' + event_type, function (data) {
1268
1269		$popupwidget = showPopupWidget('Events Calendar', data, function () {
1270			$me.attr('open', 'no');
1271		});
1272
1273		initToggles();
1274
1275		$popupwidget.find('#type_all').change(function () {
1276			if ($(this).is(':checked')) $popupwidget.find('#types_list [id^=type_]').attr('checked', false);
1277		});
1278		$popupwidget.find('#types_list [id^=type_]').change(function () {
1279			if ($(this).is(':checked')) $popupwidget.find('#type_all').attr('checked', false);
1280		});
1281		$popupwidget.find('#group_all').change(function () {
1282			if ($(this).is(':checked')) $popupwidget.find('#groups_list [id^=group_]').attr('checked', false);
1283		});
1284		$popupwidget.find('#groups_list [id^=group_]').change(function () {
1285			if ($(this).is(':checked')) $popupwidget.find('#group_all').attr('checked', false);
1286		});
1287		$popupwidget.find('#loc_all').change(function () {
1288			if ($(this).is(':checked')) $popupwidget.find('#location_list [id^=loc_]').attr('checked', false);
1289		});
1290		$popupwidget.find('#location_list [id^=loc_]').change(function () {
1291			if ($(this).is(':checked')) $popupwidget.find('#loc_all').attr('checked', false);
1292		});
1293		$me.attr('open', 'yes');
1294
1295		var onupdate = function () {
1296			var options = {};
1297			var currentDate = $popupwidget.find('#datepicker').datepicker('getDate');
1298
1299			$popupwidget.find('.eecallistheaderdate p').text(getSizedDate(currentDate));
1300
1301			$popupwidget.find('.eedate').text($.datepicker.formatDate('dd', currentDate));
1302
1303
1304			options.date = currentDate.getFullYear() + '-' + (currentDate.getMonth() + 1) + '-' + currentDate.getDate();
1305			if (!$popupwidget.find('#loc_all').is(':checked')) {
1306				options.locations = [];
1307				$popupwidget.find('#location_list [id^=loc_]').each(function () {
1308					if ($(this).is(':checked')) options.locations.push($(this).attr('id').substr(4));
1309				});
1310			}
1311			if (!$popupwidget.find('#group_all').is(':checked')) {
1312				options.groups = [];
1313				$popupwidget.find('#groups_list [id^=group_]').each(function () {
1314					if ($(this).is(':checked')) options.groups.push(encodeURIComponent($(this).attr('value')));
1315				});
1316			}
1317			if (!$popupwidget.find('#type_all').is(':checked')) {
1318				options.types = [];
1319				$popupwidget.find('#types_list [id^=type_]').each(function () {
1320					if ($(this).is(':checked')) options.types.push(encodeURIComponent($(this).attr('value')));
1321				});
1322			}
1323			$.getJSON('/eeventcaldata?event_type=' + event_type + '&req=' + encodeURIComponent(JSON.stringify(options)), function (data) {
1324				var $list = $popupwidget.find('#eecallistbody');
1325				$list.empty();
1326				$.each(data, function (value, key) {
1327					var $item = $('<div class="eelistevent"></div>');
1328
1329					$item.append('<div class="eelisttitle">' + key.title + '</div>');
1330					$item.append('<div class="linkcolour eelocation"><i class="am-locations"></i> ' + key.location + '</div>');
1331					$item.append('<div class="eelisttime headingtext">' + key.start_time + ' - ' + key.end_time + '</div>');
1332					if (key.ages) $item.append('<div class="eelistgroup">' + key.ages + '</div>');
1333					if (key.tags) $item.append('<div class="eelisttags">' + key.tags + '</div>');
1334					$item.append('<div class="eelistdesc">' + key.description + '</div>');
1335					if (parseInt(key.allow_reg, 10) === 1) {
1336						if (moment(key.close_registration).diff() < 0) {
1337							$item.append('<div class="regclosed">Registration now closed</div>');
1338						} else {
1339							if (parseInt(key.staff_only_registration, 10) === 1) {
1340								$item.append('<div class="regclosed eventStaffRegMessage">Please contact the library to register for this event</div>');
1341							} else if (parseInt(key.total_registrants, 10) >= parseInt(key.max_attendee, 10) && parseInt(key.allow_waitlist, 10) === 0) {
1342								$item.append('<div class="regclosed">This event is full</div>');
1343							} else {
1344								var event_id = key.id;
1345								var location_id = key.location_id;
1346								var m = parseInt(key.total_registrants, 10) >= parseInt(key.max_attendee, 10) ? 'Join the wait list' : 'Register';
1347								var regstatus = parseInt(key.total_registrants, 10) >= parseInt(key.max_attendee, 10) ? '0' : '1';
1348
1349								$item.append($('<div class="button eventRegButton">' + m + '</div>').on('click', function () {
1350									var $data = $('<div class="eventregform"></div>');
1351									$data.append($('.eelisttitle', $(this).closest('.eelistevent')).clone());
1352									$data.append($('.eelisttime', $(this).closest('.eelistevent')).clone());
1353									$data.append($('.eelistgroup', $(this).closest('.eelistevent')).clone());
1354									$data.append($('.eelisttags', $(this).closest('.eelistevent')).clone());
1355									$data.append($('.eelistdesc', $(this).closest('.eelistevent')).clone());
1356
1357									var $form = $('<div class="popupform"></div>');
1358									$data.append($form);
1359									$form.append(formPair('name', 'Name'));
1360									$form.append(formPair('tel', 'Telephone'));
1361									$form.append(formPair('email', 'Email'));
1362
1363									$form.append($('<div class="button eventRegButton">Submit</div>').on('click', function () {
1364										var btn = this;
1365										$('.formerr', $form).remove();
1366										var ok = true;
1367										if ($('#name', $form).val().length === 0) {
1368											$('#name', $form).parent().append('<div class="formerr">Name is required</div>');
1369											ok = false;
1370										}
1371										if ($('#tel', $form).val().length === 0 && $('#email', $form).val().length === 0) {
1372											$('#email', $form).parent().append('<div class="formerr">A telephone number or email address is required</div>');
1373											ok = false;
1374										}
1375										if (ok) {
1376											$.post('/eeventcaldata', {
1377												name: $('#name', $form).val(),
1378												tel: $('#tel', $form).val(),
1379												email: $('#email', $form).val(),
1380												event_id: event_id,
1381												status: regstatus,
1382												location_id: location_id
1383											}, function (data, textStatus, xhr) {
1384												$('.popupwidgetclose').trigger('click');
1385											});
1386										}
1387									}));
1388
1389									$popupwidget = showPopupWidget('Register for event', $data);
1390									$popupwidget.css('width', '460px');
1391									$popupwidget.position({
1392										of: $(window)
1393									});
1394								}));
1395							}
1396						}
1397					}
1398					$list.append($item);
1399				});
1400				if (data.length === 0) $list.html('<div class="eelisttitle" style="margin-left:20px">Sorry there are no events that match your selection.</div>');
1401				$('.temp_mask').css({
1402					height: $(document).height()
1403				});
1404			});
1405		};
1406		$popupwidget.find('#datepicker').datepicker({
1407			onSelect: onupdate,
1408			minDate: '0'
1409		});
1410		$popupwidget.find(':checkbox').change(onupdate);
1411
1412		$popupwidget.find('.eeback').disableSelection();
1413		$popupwidget.find('.eeback').click(function () {
1414			var d = $popupwidget.find('#datepicker').datepicker('getDate');
1415			d.setDate(d.getDate() - 1);
1416			$popupwidget.find('#datepicker').datepicker('setDate', d);
1417			onupdate();
1418		});
1419		$popupwidget.find('.eenext').disableSelection();
1420		$popupwidget.find('.eenext').click(function () {
1421			var d = $popupwidget.find('#datepicker').datepicker('getDate');
1422			d.setDate(d.getDate() + 1);
1423			$popupwidget.find('#datepicker').datepicker('setDate', d);
1424			onupdate();
1425		});
1426
1427		$popupwidget.find('.eetoday').disableSelection();
1428		$popupwidget.find('.eetoday').click(function () {
1429			$popupwidget.find('#datepicker').datepicker('setDate', new Date());
1430			onupdate();
1431		});
1432
1433		$popupwidget.find('.eetomorrow').disableSelection();
1434		$popupwidget.find('.eetomorrow').click(function () {
1435			var d = new Date();
1436			d.setDate(d.getDate() + 1);
1437			$popupwidget.find('#datepicker').datepicker('setDate', d);
1438			onupdate();
1439		});
1440		$('.eefilter', $popupwidget).on('click', function () {
1441			var $col = $('.eecalleftcol', $(this).closest('.widgetbody'));
1442			if ($col.is(':visible')) {
1443				$col.fadeOut(function () {
1444					$(this).removeAttr('style');
1445				});
1446			} else {
1447				var pos = $(this).position();
1448				var width = $(this).outerWidth();
1449				$col.css({
1450					'z-index': 1,
1451					top: pos.top + "px",
1452					left: (pos.left + width) + "px"
1453				}).slideDown();
1454
1455				//                $col.position({ my: "left top", at: "right top", of: $(this)}).slideDown();
1456			}
1457		});
1458		$('.eeclosefilter', $popupwidget).on('click', function () {
1459			$('.eecalleftcol', $(this).closest('.widgetbody')).fadeOut(function () {
1460				$(this).removeAttr('style');
1461			});
1462		});
1463		var def = $me.attr('default');
1464		if (!def) def = 'all';
1465		if (def && def != 'all') $popupwidget.find('#loc_' + def).trigger('click');
1466		if (def && def == 'all') $popupwidget.find('#loc_all').trigger('click');
1467
1468		if ($me.attr('date')) $popupwidget.find('#datepicker').datepicker('setDate', new Date(parseInt($me.attr('date')) * 1000));
1469
1470		onupdate();
1471
1472		$popupwidget.position({
1473			of: $(window)
1474		});
1475		if ($popupwidget.position().top < 0) $popupwidget.css('top', '0px');
1476		if ($(window).scrollTop() > $popupwidget.position().top) $popupwidget.css('top', $(window).scrollTop() + 'px');
1477
1478	});
1479}
1480
1481function formPair(name, label, type) {
1482	if (!type) type = 'text';
1483	return $('<div class="formpair"><label for="' + name + '">' + label + '</label><input name="' + name + '" id="' + name + '" type="' + type + '"></input></div>');
1484}
1485
1486function initeEventPopupLinks() {
1487	$('.eeventlink').click(function () {
1488		var $me = $(this);
1489		if ($me.attr('open') == 'yes') return;
1490		eEventPopup(this);
1491		return false;
1492	});
1493}
1494
1495function initPopupLinks() {
1496	$('.popup_widget').click(function () {
1497
1498		$.get('/wget?' + $(this).attr('id'), function (data) {
1499			$popupwidget = $(data);
1500			$popupwidget.addClass('popupwidget');
1501			$close = $('<div class="popupwidgetclose"><i class="fa fa-times"></i></div>');
1502			$popupwidget.find('.widgetheader').append($close);
1503
1504			var maskHeight = $(document).height();
1505			var maskWidth = $(window).width();
1506
1507			var $mask = $('<div class="temp_mask"></div>').hide();
1508			$mask.css({
1509				'z-index': 15,
1510				'width': maskWidth,
1511				'height': maskHeight,
1512				backgroundColor: '#000000',
1513				position: 'absolute',
1514				top: '0px',
1515				left: '0px'
1516			});
1517			$('body').append($mask);
1518
1519			var closefunc = function () {
1520				$mask.last().fadeOut(200, function () {
1521					$(this).remove()
1522				});
1523				$popupwidget.last().fadeOut(200, function () {
1524					$(this).remove()
1525				});
1526			};
1527			$mask.click(closefunc);
1528			$close.click(closefunc);
1529
1530
1531			$('body').append($popupwidget);
1532			$popupwidget.position({
1533				of: $(window)
1534			});
1535
1536
1537			$popupwidget.fadeIn(200);
1538			$mask.fadeTo('slow', 0.5);
1539			if ($popupwidget.position().top < 0) $popupwidget.css('top', '0px');
1540
1541		});
1542		return false;
1543	});
1544}
1545
1546function initButtonWidgets() {
1547	$('.buttontable').each(function () {
1548		$(this).find('tr').each(function () {
1549			var $button = $(this).find('button');
1550			var $link = $(this).find('a');
1551			$link.mouseover(function () {
1552				$button.addClass('button_open');
1553			});
1554			$link.mouseout(function () {
1555				$button.removeClass('button_open');
1556			});
1557		});
1558	});
1559}
1560function initNYPLCollections() {
1561	$('ul.nyplcollection').each(function () {
1562		var $nyplcollections = $(this);
1563		$nyplcollections.hide();
1564		var items = [];
1565		$('li', $nyplcollections).each(function (idx, item) {
1566			items.push({ id: $(item).data('id') });
1567		});
1568		var pos = 0;
1569
1570		var stage = $('<div>').addClass('nyplcollection-stage').css({ 'position': 'relative', 'height': '100%', 'width': '100%' }).appendTo($nyplcollections.closest('.widgetbody'));
1571		var image = $('<div class="nyplcollection-image"><div></div></div>').appendTo(stage);
1572		var info = $('<div class="nyplcollection-info"></div>').appendTo(stage);
1573		var description = $('<div class="nyplcollection-description"></div>').appendTo(info);
1574		var title = $('<div class="nyplcollection-title"></div>').appendTo(description);
1575		var creator = $('<div class="nyplcollection-creator"></div>').appendTo(description);
1576		var dateCreated = $('<div class="nyplcollection-date-created"></div>').appendTo(description);
1577		var division = $('<div class="nyplcollection-division"></div>').appendTo(description);
1578		var imageId = $('<div class="nyplcollection-image-id"></div>').appendTo(description);
1579		var footer = $('<div class="nyplcollection-footer"></div>').appendTo(stage);
1580		var qrcode = $('<div class="nyplcollection-qrcode"><div></div></div>').appendTo(footer);
1581		$('<div class="nyplcollection-message"><div class="nyplcollection-message-title">Explore NYPL\'s Digital Collections</div><div>Get free access to more than 900,000 items digitized from our world-renowned collections, including prints, photographs, maps, manuscripts, video, and more, with new materials added every day.</div></div>').appendTo(footer);
1582
1583		function render(item) {
1584			$(title).text(item.data.title);
1585			$(creator).text(item.data.creator);
1586			$(dateCreated).text(item.data.dateCreated);
1587			$(division).text(item.data.division);
1588			$(imageId).text('Image ID:' + item.data.imageId);
1589			$('>div', image).css({ 'background-image': 'url("https://images.nypl.org/index.php?id=' + item.data.imageId + '&t=w")' });
1590			$('>div', qrcode).css({ 'background-image': 'url("https://chart.googleapis.com/chart?cht=qr&chl=' + encodeURIComponent(item.data.url) + '&chs=150x150&chf=bg,s,58595b&chco=58595b&chld=L|0")' });
1591		}
1592		function setItem(item) {
1593			if (!item.data) {
1594				$.getJSON('/nyplitem?id=' + item.id).then(function (data) {
1595					if (data.numResults.$ === '0') {
1596						item.notFound = true;
1597						pos++;
1598						setItem(items[pos]);
1599						return;
1600					}
1601					var capture = Array.isArray(data.capture) ? data.capture.shift() : data.capture;
1602
1603					var division = Array.isArray(data.mods.location) ? data.mods.location.filter(function (l) { l.type === 'division' }).map(function (c) {
1604						return c.physicalLocation.$
1605					}).shift() : data.mods.location.physicalLocation.$;
1606
1607					var originInfo = Array.isArray(data.mods.originInfo) ? data.mods.originInfo[0] : data.mods.originInfo;
1608
1609					var name = Array.isArray(data.mods.name) ? data.mods.name[0] : data.mods.name;
1610					if (name) name = name.namePart.$;
1611
1612					var titleInfo = Array.isArray(data.mods.titleInfo) ? data.mods.titleInfo[0] : data.mods.titleInfo;
1613					item.data = {
1614						title: titleInfo.title.$,
1615						dateCreated: originInfo.dateCreated ? originInfo.dateCreated.$ : originInfo.dateIssued.$,
1616						creator: name,
1617						division: division,
1618						imageUUID: capture.uuid.$,
1619						imageId: capture.imageID.$,
1620						url: 'https://digitalcollections.nypl.org/items/' + capture.uuid.$ + '#/?uuid=' + capture.uuid.$,
1621					}
1622					render(item);
1623				});
1624			} else {
1625				render(item);
1626			}
1627		}
1628
1629		setItem(items[pos]);
1630		setInterval(function () {
1631			pos++;
1632			if (pos >= items.length) {
1633				pos = 0;
1634			}
1635			while (items[pos].notFound) {
1636				pos++;
1637			}
1638			setItem(items[pos]);
1639		}, parseInt($nyplcollections.data('delay')));
1640	});
1641}
1642function iniResItems() {
1643	$('.resitem').each(function () {
1644		var $resItem = $(this);
1645		var $header = $resItem.children('.resource_item_header');
1646		var $body = $resItem.children('.resbody');
1647		if ($resItem.hasClass('resource_item_open')) {
1648			$header.attr('aria-expanded', 'true');
1649			$body.attr('aria-hidden', 'false');
1650		} else {
1651			$header.attr('aria-expanded', 'false');
1652			$body.attr('aria-hidden', 'true');
1653		}
1654		var style = $(this).attr('viewstyle');
1655		switch (style) {
1656			case '1':
1657			case '2':
1658			case '3':
1659				$(this).click(function () {
1660					var $content = $('<div class="popupres"/>');
1661					$(this).children('.resbody').children('.ressection').each(function () {
1662					var $item = $(this).clone();
1663					$item.show();
1664					$content.append($item);
1665				});
1666				showPopupWidget($(this).children('.resource_item_header').text(), $content);
1667					$content.shapeshift({
1668						enableDrag: false
1669					});
1670				});
1671				break;
1672		default:
1673			(function () {
1674				var toggleSection = function () {
1675					if ($resItem.hasClass('resource_item_open')) {
1676						$header.attr('aria-expanded', 'false');
1677						$body.attr('aria-hidden', 'true');
1678						$body.slideUp(300, function () {
1679							$resItem.removeClass('resource_item_open');
1680						});
1681						return;
1682					}
1683					$('.resource_item_open').each(function () {
1684						var $sec = $(this);
1685						var $secHeader = $sec.children('.resource_item_header');
1686						var $secBody = $sec.children('.resbody');
1687						$secHeader.attr('aria-expanded', 'false');
1688						$secBody.attr('aria-hidden', 'true');
1689						$secBody.slideUp(300, function () {
1690							$sec.removeClass('resource_item_open');
1691						});
1692					});
1693					$resItem.addClass('resource_item_open');
1694					$header.attr('aria-expanded', 'true');
1695					$body.attr('aria-hidden', 'false');
1696					$body.slideDown();
1697				};
1698
1699				var handleActivation = function (event) {
1700					if (event.type === 'keydown') {
1701						var key = event.which || event.keyCode;
1702						if (key !== 13 && key !== 32) {
1703							return;
1704						}
1705						event.preventDefault();
1706					}
1707					toggleSection();
1708				};
1709
1710				$header.off('.resourceToggle');
1711				$header.on('click.resourceToggle', handleActivation);
1712				$header.on('keydown.resourceToggle', handleActivation);
1713			})();
1714			break;
1715		}
1716	});
1717}
1718
1719function initVideo() {
1720	var self = this;
1721	$('.video_player').each(function () {
1722
1723		function videoIdFromURL(url) {
1724			var regExp = /^.*(youtu\.be\/|v\/|u\/\w\/|embed\/|watch\?v=|\&v=)([^#\&\?]*).*/;
1725			var match = url.match(regExp);
1726			if (match && match[2].length == 11) {
1727				return match[2];
1728			} else {
1729				return false;
1730			}
1731		}
1732
1733		var config_obj = $(this).data('video');
1734
1735		if (typeof config_obj.video_service !== 'undefined' && config_obj.video_service == "Vimeo") {
1736
1737			var this_widget = $(this)[0].parentNode.parentNode;
1738
1739			var vidHeight = $(this_widget).css('height');
1740			var vidWidth = $(this_widget).css('width');
1741
1742			var tag = document.createElement('script');
1743			tag.src = "https://player.vimeo.com/api/player.js";
1744			var firstScriptTag = document.getElementsByTagName('script')[0];
1745			firstScriptTag.parentNode.insertBefore(tag, firstScriptTag);
1746
1747			// Working around bug
1748			var waitForVimeo = function (callback) {
1749				var checkVimeo = function () {
1750					if (typeof window.Vimeo === 'undefined') {
1751						return false;
1752					} else {
1753						return true;
1754					}
1755				};
1756				if (checkVimeo()) {
1757					callback();
1758				} else {
1759					var interval = setInterval(function () {
1760						if (checkVimeo()) {
1761							clearInterval(interval);
1762							callback();
1763						}
1764					}, 700);
1765				}
1766			};
1767
1768			waitForVimeo(function () {
1769
1770				var result = config_obj.vimeo_url.match(/(?:www\.|player\.)?vimeo.com\/(?:channels\/(?:\w+\/)?|groups\/(?:[^\/]*)\/videos\/|album\/(?:\d+)\/video\/|video\/|)(\d+)(?:[a-zA-Z0-9_\-]+)?/i);
1771
1772				if (!(result && Array.isArray(result) && result[1])) {
1773					return;
1774				}
1775
1776				var video_id = result[1];
1777
1778				var options = {
1779					id: video_id,
1780					height: (window.innerHeight - (window.innerHeight * .05)), // 95% height
1781					loop: false,
1782				};
1783
1784				var player = new Vimeo.Player('player', options);
1785
1786				// Autostart
1787				player.on("loaded", function () {
1788					if (typeof config_obj.vimeo.start !== 'undefined' && config_obj.vimeo.start > 0) {
1789						player.setCurrentTime(config_obj.vimeo.start);
1790					} else {
1791						player.setCurrentTime(0);
1792					}
1793					if (config_obj.vimeo.autostart == "1") {
1794						player.play();
1795					}
1796				});
1797
1798				player.on("play", function (e) {
1799
1800					var endPoint = e.duration;
1801					if (typeof config_obj.vimeo.end !== 'undefined' && config_obj.vimeo.end) {
1802						endPoint = config_obj.vimeo.end;
1803					}
1804
1805
1806					player.addCuePoint(endPoint, {
1807						customKey: 'customValue'
1808					});
1809
1810				});
1811
1812				player.on("cuepoint", function (e) {
1813					player.removeCuePoint(e.id).then(function (id) {
1814						player.pause();
1815					});
1816				});
1817
1818				if (config_obj.vimeo.captions == "1") {
1819					player.enableTextTrack('en').then(function (track) {
1820					});
1821				} else if (config_obj.vimeo.captions == "0") {
1822					player.disableTextTrack().then(function () {
1823					});
1824				}
1825
1826				if (config_obj.vimeo.mute == "1") {
1827					player.setVolume(0);
1828				}
1829
1830			});
1831
1832		} else if (typeof config_obj.video_service === 'undefined' || config_obj.video_service == "YouTube") {
1833
1834			config_obj.yt['playlist'] = videoIdFromURL(config_obj.youtube_url);
1835
1836			var tag = document.createElement('script');
1837			tag.src = "https://www.youtube.com/player_api";
1838			var firstScriptTag = document.getElementsByTagName('script')[0];
1839			firstScriptTag.parentNode.insertBefore(tag, firstScriptTag);
1840
1841			var this_widget = $(this)[0].parentNode.parentNode;
1842
1843			var play_yt = function () {
1844
1845				var vidHeight = $(this_widget).css('height');
1846				var vidWidth = $(this_widget).css('width');
1847
1848				var player = new YT.Player('player', {
1849					enablejsapi: "1",
1850					playerVars: config_obj.yt,
1851					height: (window.innerHeight - (window.innerHeight * .05)), // 95% height
1852					width: "100%",
1853					videoId: videoIdFromURL(config_obj.youtube_url),
1854					events: {
1855						'onApiChange': function (event) {
1856						},
1857						'onReady': function (event) {
1858						},
1859						'onStateChange': function (event) {
1860
1861							if (event.data == YT.PlayerState.PLAYING) {
1862								if (typeof config_obj.caption_size !== 'undefined' && config_obj.caption_size !== 0) {
1863									if (typeof player.setOption == 'function') {
1864										player.setOption('captions', 'fontSize', config_obj.caption_size);
1865									}
1866								}
1867							}
1868							if (event.data == YT.PlayerState.ENDED) {
1869								if (config_obj.youtube_loop != "1") {
1870									if (typeof player.stopVideo() == 'function') {
1871										player.stopVideo();
1872									}
1873								}
1874							}
1875						}
1876					}
1877				});
1878			}
1879		}
1880
1881		// This is to work around buggy youtube api
1882		if (window.initialPlay == false) {
1883			play_yt();
1884		}
1885
1886		window.onYouTubePlayerAPIReady = function () {
1887			window.initialPlay = false;
1888			play_yt();
1889		}
1890	});
1891}
1892
1893function initTwitter() {
1894	$('.twitter').each(function () {
1895		var username = $(this).attr('id');
1896		if (username.length === 0) return;
1897		$(this).tweet({
1898			modpath: '/tw/index.php',
1899			username: username,
1900			avatar_size: 48,
1901			count: 5,
1902			loading_text: 'loading twitter feed...'
1903		});
1904	});
1905}
1906
1907function iniRSSWidgets(id) {
1908	var $list = $(id).find('.rssslist');
1909	var feedstyle = $list.attr('data-viewstyle') ? parseInt($list.attr('data-viewstyle'), 10) : 0;
1910	var count = $list.attr('data-count') ? parseInt($list.attr('data-count'), 10) : 5;
1911
1912	$list.hide();
1913	var multi = ($list.find('a').length > 1) ? true : false;
1914	var $rsstabbar = $('<div class="widget_tab_bar"></div>');
1915	if (multi) {
1916		$(id).append($rsstabbar);
1917	}
1918	var i = 0;
1919	$list.find('a').each(function () {
1920		var $tab = $('<div id="id_' + i + '" class="widget_tab">' + $(this).text() + '</div>');
1921		var $feed = $('<div class="feed" id="id_' + i + '_feed"></div>');
1922		$.getJSON('/rss', { feed: $(this).attr('href') }, function (json) {
1923			var $body = $('<div class="rssBody"></div>').appendTo($feed);
1924			var $rssList = $('<ul></ul>').appendTo($body);
1925			if (json.result) {
1926				$feed.addClass('rssFeed');
1927				var t = 'even';
1928				var i = 0;
1929				$.each(json.data.item, function (idx, item) {
1930					i++;
1931					if (i > count) return;
1932					var $item = $('<li class="rssRow ' + t + '"></li>');
1933					if (item.description) {
1934						$item.attr('data-desc', item.description).appendTo($rssList).qtip({
1935							content: {
1936								attr: 'data-desc'
1937							},
1938							position: {
1939								my: 'left top',
1940								at: 'right top',
1941								viewport: $(window),
1942								target: 'mouse',
1943								adjust: {
1944									mouse: false
1945								}
1946							},
1947							events: {
1948								show: function (event, api) {
1949									if ($(window).width() <= 768) {
1950										return false;
1951									}
1952								}
1953							}
1954						});
1955					}
1956					$('<h4><a target="_system" href="' + item.link + '">' + item.title + '</a></h4>').appendTo($item);
1957					if (item.date) {
1958						$('<div>' + moment(item.date).format('LLL') + '</div>').appendTo($item);
1959					}
1960					t = t == "odd" ? "even" : "odd";
1961				});
1962			} else {
1963				$feed.html('Error loading feed');
1964			}
1965		});
1966		// $feed = $('<div class="feed" id="id_' + i + '_feed"></div>').rssfeed($(this).attr('href'), {
1967		// 		limit: count,
1968		// 		header: true,
1969		// 		snippet: feedstyle === 0,
1970		// 		linktarget: '_system'
1971		// 	}, function(feed) {
1972		// 		if (feedstyle === 1) $(feed).find('.rssBody').addClass('imgfeed');
1973		// 		$(feed).find('.rssHeader').appendTo(feed);
1974		// 		$(feed).find('.rssRow').each(function() {
1975		// 			if (feedstyle === 0) {
1976		// 				$(this).attr('desc', $('p:first', this).html());
1977		// 			} else {
1978		// 				var link = $('h4:first a', this);
1979		// 				link.html($('img:first', this));
1980		// 				$(this).empty().append(link);
1981		// 			}
1982		// 		});
1983		// 		if (feedstyle === 0) {
1984		// 			$('.widgetbody').find('.rssRow[desc]').qtip({
1985		// 				content: {
1986		// 					attr: 'desc'
1987		// 				},
1988		// 				position: {
1989		// 					my: 'left top',
1990		// 					at: 'right top',
1991		// 					viewport: $(window)
1992		// 				},
1993		// 				events: {
1994		// 					show: function(event, api) {
1995		// 						if ($(window).width() <= 768) {
1996		// 							return false;
1997		// 						}
1998		// 					}
1999		// 				}
2000		// 			});
2001		// 		}
2002		// 	});
2003		if (multi) {
2004			$feed.hide();
2005			$tab.click(function () {
2006				$(this).parent().find('.widget_tab_selected').removeClass('widget_tab_selected');
2007				$(this).addClass('widget_tab_selected');
2008				$(this).parent().parent().find('.feed').hide();
2009				$(this).parent().parent().find('#' + $(this).attr('id') + '_feed').fadeIn();
2010			});
2011		}
2012		$rsstabbar.append($tab);
2013		$(id).append($feed);
2014		i++;
2015	});
2016	$(id).find('.widget_tab:first').addClass('widget_tab_selected');
2017	$(id).find('.feed:first').show();
2018}
2019
2020function showPopupWidget(title, content, closedCallback) {
2021	var $popupwidget = $('<div class="popupwidget widget"></div>').hide();
2022	$popupwidget.css('z-index', 200 * ($('.popupwidget').length + 1));
2023
2024	$header = $('<div class="widgetheader">' + title + '</div>');
2025	$close = $('<div class="popupwidgetclose"><i class="fa fa-times"></i></div>');
2026
2027	$header.append($close);
2028	$popupwidget.append($header);
2029
2030	$popupwidgetbody = $('<div class="widgetbody"></div>');
2031	$popupwidgetbody.append(content);
2032	$popupwidget.append($popupwidgetbody);
2033
2034	var maskHeight = $(document).height();
2035	var maskWidth = $(window).width();
2036
2037	var zindex = 150 * ($('.temp_mask').length + 1);
2038
2039	var $mask = $('<div class="temp_mask"></div>').hide();
2040	$mask.css({
2041		'z-index': zindex,
2042		'width': maskWidth,
2043		'height': maskHeight,
2044		backgroundColor: '#000000',
2045		position: 'absolute',
2046		top: '0px',
2047		left: '0px'
2048	});
2049	$('body').append($mask);
2050
2051	var closefunc = function () {
2052		$mask.last().fadeOut(200, function () {
2053			$(this).remove()
2054		});
2055		$popupwidget.last().fadeOut(200, function () {
2056			$(this).remove()
2057		});
2058		if (closedCallback) closedCallback();
2059	};
2060	$mask.click(closefunc);
2061	$close.click(closefunc);
2062
2063
2064	$('body').append($popupwidget);
2065	$popupwidget.position({
2066		of: $(window)
2067	});
2068	$popupwidget.css('top', $(window).scrollTop() + 'px');
2069
2070	$popupwidget.fadeIn(200);
2071	$mask.fadeTo('slow', 0.5);
2072	//    if ($popupwidget.position().top < 0)$popupwidget.css('top', '0px');
2073	//    if ($(window).scrollTop() > $popupwidget.position().top)$popupwidget.css('top', $(window).scrollTop() + 'px');
2074	return $popupwidget;
2075}
2076function bingtype(type, span) {
2077	$('.span_link_s').removeClass('span_link_s');
2078	$(span).addClass('span_link_s');
2079	$('#bingtype').val(type);
2080}
2081function dosearchv2(action, sid, span) {
2082	/*  if(document.getElementById('q').value=='Search the web here...'||)return;
2083window.location.href=url+document.getElementById('q').value;*/
2084	for (var i = 0; i < span.parentNode.childNodes.length; i++) {
2085		if (span.parentNode.childNodes[i].nodeName == 'SPAN') {
2086			span.parentNode.childNodes[i].className = 'span_link';
2087		}
2088	}
2089	span.className = 'span_link_s';
2090	var q = document.getElementById('q');
2091	var search_from = document.getElementById('search_from');
2092	search_from.action = action;
2093	q.name = sid;
2094	document.forms['search_from'].submit();
2095	//  if(q.value!='Search the web here...'&&q.value!='')q.form.submit();
2096}
2097
2098function initAccordion(id) {
2099	var $accordion = $(id);
2100	var $titles = $accordion.find('.wtitle');
2101	var $panels = $accordion.find('.wbody');
2102
2103	if (!$titles.length) return;
2104
2105	var getPanel = function ($title) {
2106		var controls = $title.attr('aria-controls');
2107		if (controls) {
2108			return $('#' + controls);
2109		}
2110		return $('#' + $title.attr('id') + '_body');
2111	};
2112
2113	var collapse = function ($title, instant) {
2114		var $panel = getPanel($title);
2115		if ($panel && $panel.length) {
2116			$panel.stop(true, true);
2117			var finish = function () {
2118				$panel.removeClass('wopen').attr('aria-hidden', 'true').attr('hidden', 'hidden');
2119			};
2120			if (instant) {
2121				$panel.hide();
2122				finish();
2123			} else {
2124				$panel.slideUp(300, finish);
2125			}
2126		}
2127		$title.removeClass('button_open').attr('aria-expanded', 'false');
2128	};
2129
2130	var expand = function ($title, focusHeader, instant) {
2131		$panels.each(function () {
2132			var $panelTitle = $(this).prevAll('.wtitle').first();
2133			if ($panelTitle.length && !$panelTitle.is($title)) {
2134				collapse($panelTitle, instant);
2135			}
2136		});
2137		$titles.not($title).each(function () {
2138			if (!$(this).is($title)) {
2139				$(this).removeClass('button_open').attr('aria-expanded', 'false');
2140			}
2141		});
2142
2143		var $panel = getPanel($title);
2144		if ($panel && $panel.length) {
2145			$panel.stop(true, true);
2146			var finish = function () {
2147				$panel.addClass('wopen').attr('aria-hidden', 'false').removeAttr('hidden');
2148			};
2149			if (instant) {
2150				$panel.show();
2151				finish();
2152			} else {
2153				$panel.slideDown(300, finish);
2154			}
2155		}
2156		$title.addClass('button_open').attr('aria-expanded', 'true');
2157		if (focusHeader) {
2158			$title.focus();
2159		}
2160	};
2161
2162	var moveFocus = function ($current, offset) {
2163		var currentIndex = $titles.index($current);
2164		if (currentIndex === -1) {
2165			currentIndex = 0;
2166		}
2167		var targetIndex = (currentIndex + offset + $titles.length) % $titles.length;
2168		$titles.eq(targetIndex).focus();
2169	};
2170
2171	$titles.each(function (index) {
2172		var $title = $(this);
2173		var $panel = getPanel($title);
2174		if ($panel && $panel.length) {
2175			$panel.attr('role', $panel.attr('role') || 'region');
2176		}
2177		var expanded = $title.attr('aria-expanded') === 'true' || $title.attr('open') === 'yes';
2178		if ($title.attr('open')) {
2179			$title.removeAttr('open');
2180		}
2181		$title.attr('tabindex', '0');
2182		if (expanded) {
2183			expand($title, false, true);
2184		} else {
2185			collapse($title, true);
2186		}
2187	});
2188
2189	var $initial = $titles.filter('[aria-expanded="true"]').first();
2190	if (!$initial.length) {
2191		$initial = $titles.first();
2192		collapse($initial, true);
2193	}
2194
2195	$titles.off('.accordion');
2196	$titles.on('click.accordion', function (event) {
2197		event.preventDefault();
2198		var $title = $(this);
2199		if ($title.hasClass('button_open')) {
2200			collapse($title, false);
2201		} else {
2202			expand($title, false, false);
2203		}
2204	});
2205
2206	$titles.on('keydown.accordion', function (event) {
2207		var key = event.which || event.keyCode;
2208		var $title = $(this);
2209		switch (key) {
2210			case 13: // Enter
2211			case 32: // Space
2212				event.preventDefault();
2213				if ($title.hasClass('button_open')) {
2214					collapse($title, false);
2215				} else {
2216					expand($title, false, false);
2217				}
2218				break;
2219			case 38: // Up
2220			case 37: // Left
2221				event.preventDefault();
2222				moveFocus($title, -1);
2223				break;
2224			case 40: // Down
2225			case 39: // Right
2226				event.preventDefault();
2227				moveFocus($title, 1);
2228				break;
2229		}
2230	});
2231}
2232
2233function logStat(type, data) {
2234	// try {
2235	// 	if (navigator.sayswho) data.b = navigator.sayswho;
2236	// 	var portal = $('[data-portal]').attr('data-portal');
2237	// 	if (portal && portal.length > 0) data.portal = portal;
2238	// 	data.sid = readCookie('s');
2239	// 	$.post('/l', JSON.stringify([{
2240	// 		type: type,
2241	// 		time: new Date(),
2242	// 		data: data
2243	// 	}]));
2244	// } catch (e) {}
2245}
2246
2247function eraseCookie(name) {
2248	createCookie(name, "", -1);
2249}
2250
2251function createCookie(name, value, days) {
2252	var expires = "";
2253	if (days) {
2254		var date = new Date();
2255		date.setTime(date.getTime() + (days * 24 * 60 * 60 * 1000));
2256		expires = "; expires=" + date.toGMTString();
2257	}
2258	document.cookie = name + "=" + value + expires + "; path=/; SameSite=Strict; Secure";
2259}
2260
2261function readCookie(name) {
2262	var nameEQ = name + "=";
2263	var ca = document.cookie.split(';');
2264	for (var i = 0; i < ca.length; i++) {
2265		var c = ca[i];
2266		while (c.charAt(0) == ' ') c = c.substring(1, c.length);
2267		if (c.indexOf(nameEQ) === 0) return c.substring(nameEQ.length, c.length);
2268	}
2269	return null;
2270}
2271/*todo: rewirte flickr support!!!*/
2272var flickrLists = new Object();
2273
2274function flickrShow(list, id) {
2275	flickrLists[id] = list;
2276	var holder = document.getElementById(id);
2277	var img = document.createElement('img');
2278	holder.appendChild(img);
2279	var title = document.createElement('div');
2280	title.className = 'flickr_mini_title';
2281	title.id = id + '_mini_title';
2282	holder.appendChild(title);
2283
2284	img.setAttribute('nextimg', 0);
2285	img.setAttribute('timerstate', 1);
2286
2287	var changeFunc = function () {
2288		if (img.getAttribute('timerstate') == 0) return;
2289		var n = img.getAttribute('nextimg');
2290		if (!list[n]) n = 0;
2291		img.src = list[n].url;
2292		title.innerHTML = list[n].title;
2293		n++;
2294		img.setAttribute('nextimg', n);
2295	};
2296	changeFunc();
2297	setInterval(changeFunc, 5000);
2298}
2299
2300function flickrPauseToggle(id) {
2301	var holder = document.getElementById(id);
2302	var img = holder.firstChild;
2303	if (img.getAttribute('timerstate') == 0) {
2304		img.setAttribute('timerstate', 1);
2305	} else {
2306		img.setAttribute('timerstate', 0);
2307	}
2308}
2309
2310function flickrPrev(id) {
2311	var holder = document.getElementById(id);
2312	var img = holder.firstChild;
2313	var n = img.getAttribute('nextimg');
2314	if (n > 1) {
2315		n = n - 2;
2316	} else {
2317		n = flickrLists[id].length - 1;
2318	}
2319	img.src = flickrLists[id][n].url;
2320	var title = document.getElementById(id + '_mini_title');
2321	title.innerHTML = flickrLists[id][n].title;
2322	n++;
2323	img.setAttribute('nextimg', n);
2324}
2325
2326function flickrNext(id) {
2327	var holder = document.getElementById(id);
2328	var img = holder.firstChild;
2329	var n = img.getAttribute('nextimg');
2330	if (!flickrLists[id][n]) n = 0;
2331	img.src = flickrLists[id][n].url;
2332	var title = document.getElementById(id + '_mini_title');
2333	title.innerHTML = flickrLists[id][n].title;
2334	n++;
2335	img.setAttribute('nextimg', n);
2336}
2337
2338function flickrEnlarge(id) {
2339	var cover = isis.screenCover();
2340	cover.setColour('#FFFFFF');
2341	var holder = document.createElement('div');
2342
2343	holder.className = 'flickrPopup';
2344	holder.style.position = 'absolute';
2345	isis.fx(holder).opacity(0);
2346	document.body.appendChild(holder);
2347
2348	var popupbody = document.createElement('div');
2349	popupbody.className = 'flickrPopupBody';
2350	holder.appendChild(popupbody);
2351
2352
2353	var title = document.createElement('div');
2354	title.id = id + '_title';
2355	title.className = 'flickrTitle';
2356	popupbody.appendChild(title);
2357
2358
2359
2360	$close = $('<i class="icon-zoom-out icon-2x"></i>');
2361	$close.css('float', 'right');
2362	$close.css('cursor', 'pointer');
2363
2364	$(popupbody).append($close);
2365	$close.on('click', function () {
2366		isis.fx(holder, {
2367			'finishedCallback': function () {
2368				if (holder.parentNode) holder.parentNode.removeChild(holder);
2369			}
2370		}).tween("opacity:0");
2371		cover.distroy();
2372	});
2373
2374	var closet = document.createElement('img');
2375	closet.src = '/images/common/flikr/flickr-c.png';
2376	closet.style.cssFloat = 'right';
2377	closet.style.styleFloat = 'right';
2378	popupbody.appendChild(closet);
2379
2380	var stage = document.createElement('div');
2381	stage.className = 'flickrStage';
2382	popupbody.appendChild(stage);
2383
2384	var canvas = document.createElement('div');
2385	canvas.className = 'flickrCanvas';
2386	canvas.id = id + '_canvas';
2387	stage.appendChild(canvas);
2388
2389
2390	var thumbs = document.createElement('div');
2391	thumbs.className = 'flickrThumbs';
2392	stage.appendChild(thumbs);
2393
2394
2395	for (var i = 0; i < flickrLists[id].length; i++) {
2396		var img = document.createElement('img');
2397		img.src = flickrLists[id][i].small;
2398		thumbs.appendChild(img);
2399		var img_n = i;
2400		img.setAttribute('img_n', i);
2401		img.setAttribute('set_id', id);
2402		isis.addEventHandler(img, 'click', function (e) {
2403			if (!e.currentTarget) e.currentTarget = e.srcElement;
2404			showFlickrImage(e.currentTarget);
2405		});
2406	}
2407
2408
2409	var footer = document.createElement('div');
2410	footer.className = 'flickrFooter';
2411	stage.appendChild(footer);
2412
2413	var logo = document.createElement('img');
2414	logo.src = '/images/common/flikr/flickr.png';
2415	logo.style.marginTop = '15px';
2416	logo.style.cssFloat = 'right';
2417	logo.style.styleFloat = 'right';
2418	footer.appendChild(logo);
2419
2420	holder.style.top = (isis.getScrollTop() + (isis.getClientHeight() - holder.offsetHeight) / 2) + 'px';
2421	holder.style.left = (isis.getScrollLeft() + (isis.getClientWidth() - holder.offsetWidth) / 2) + 'px';
2422
2423
2424	isis.addEventHandler(cover.holder, 'click', function (e) {
2425		isis.fx(holder, {
2426			'finishedCallback': function () {
2427				if (holder.parentNode) holder.parentNode.removeChild(holder);
2428			}
2429		}).tween("opacity:0");
2430		cover.distroy();
2431	});
2432
2433	var h = document.getElementById(id);
2434	var img = h.firstChild;
2435	var n = img.getAttribute('nextimg');
2436	n--;
2437	if (!flickrLists[id][n]) n = 0;
2438	_showFlickrImage(id, n);
2439
2440	cover.show();
2441	isis.fx(holder).tween("opacity:1");
2442
2443}
2444
2445function _showFlickrImage(id, img_n) {
2446	var canvas = document.getElementById(id + '_canvas');
2447	var title = document.getElementById(id + '_title');
2448
2449	while (canvas.firstChild) canvas.removeChild(canvas.firstChild);
2450	var img = document.createElement('img');
2451	img.src = flickrLists[id][img_n].large;
2452	img.style.border = '1px solid #a1a1a1';
2453	canvas.appendChild(img);
2454	canvas.appendChild(document.createElement('br'));
2455	var desc = document.createElement('div');
2456	desc.innerHTML = flickrLists[id][img_n].desc;
2457	canvas.appendChild(desc);
2458
2459	title.innerHTML = flickrLists[id][img_n].title;
2460
2461}
2462
2463function showFlickrImage(img) {
2464	var img_n = img.getAttribute('img_n');
2465	var id = img.getAttribute('set_id');
2466	_showFlickrImage(id, img_n);
2467}
2468
2469function getFormatClassFromName(name) {
2470	name = name.toLowerCase();
2471	switch (name) {
2472		case 'book': return "am-book-format";
2473		case 'dvd': return "am-dvd-format";
2474		case 'video': return "am-video-format";
2475		case 'ebook': return "am-ebook-format";
2476		case 'audiobook': return "am-audiobook-format";
2477		default: return "";
2478	}
2479}
2480function getIconClassFromName(name) {
2481	name = name.toLowerCase();
2482	switch (name) {
2483		case 'book': return "cover-book-format";
2484		case 'dvd': return "cover-dvd-format";
2485		case 'video': return "cover-video-format";
2486		case 'ebook': return "cover-ebook-format";
2487		case 'audiobook': return "cover-audiobook-format";
2488		default: return "";
2489	}
2490}
2491
2492function coverLoaded(img) {
2493	if (img.clientWidth == 1) {
2494		$(img).attr('src', '/images/item-placeholder-back.png');
2495	}
2496}
2497
2498function polarisReserve(book_id) {
2499	var client = $('meta[name=client]').attr('content');
2500	var login = readCookie('loginData');
2501	if (login) {
2502		login = $.parseJSON(decodeURIComponent(login));
2503
2504	} else {
2505
2506	}
2507}
2508function editRegistration() {
2509
2510}
2511$.fn.amEditReg = function (options) {
2512	this.each(function (index, el) {
2513		var self = $(this);
2514		if (!self.data('amEditReg')) {
2515			self.data('amEditReg', true);
2516			self.options = $.extend({}, $.fn.amEditReg.defaults, options);
2517			self.element = el;
2518			self.$element = $(el);
2519			self.apiServer = $('meta[name=apiserver]').attr('content') || 'https://api.communico.co';
2520			self.keyword = $('meta[name=client]').attr('content');
2521			self.guests = [];
2522			self.master_id = $(this).closest('.row').prev('.ammev-reservation').attr('data-id');
2523
2524			self.$element.on('click', function (event) {
2525				event.preventDefault();
2526				self.master_id = $(this).closest('.row').prev('.ammev-reservation').attr('data-id');
2527				$.getJSON('/myevents', { masterid: self.master_id, ref: self.options.ref, action: 'list' }, function (json, textStatus) {
2528					self.initialGuestsCount = json.length;
2529					self.guests = json;
2530					var popup = $('<div class="events2-reg-popup"></div>').amPopup({ title: 'Guest registrations' });
2531					var stage = $('<div class="events2-reg-stage"></div>').appendTo(popup);
2532					var footer = $('<div class="events2-reg-footer"></div>').appendTo(popup);
2533					// Guests are view-only for billed and multiple-registration-type
2534					// events (no add/remove controls) — saving from that mode rewrites
2535					// the guest rows and severs their ticket data, so offer no save.
2536					if (+self.options.enableBilling === 0 && +self.options.enableMultipleTypes === 0) {
2537						var button = $('<button class="btn btn-primary"></button>').text('save').on('click', function (event) {
2538							event.preventDefault();
2539							$.getJSON('/myevents', { masterid: self.master_id, ref: self.options.ref, action: 'save', guests: JSON.stringify(self.guests) }, function (json, textStatus) {
2540								if (json.status == 'ok') {
2541									popup.data('plugin_amPopup').close();
2542									// Reconcile the booking's row in place rather than navigating.
2543									// A card/pin sign-in only renders its registration list as the
2544									// response to the login POST, so any navigation drops the patron
2545									// out of that list and onto a single-registration view.
2546									var reservation = self.$element.closest('.row').prev('.ammev-reservation');
2547									var registrants = 1 /* the patron that registered */ + self.guests.length;
2548									reservation.find('.ammev-registrants').text(registrants + ' registrant' + (registrants > 1 ? 's' : '') + ' on this booking');
2549									// data-total-registrants is the event-wide count as at page
2550									// render, and feeds the add-guest seat check; shift it by this
2551									// booking's delta so it stays accurate without a reload.
2552									var totalRegistrants = parseInt(self.options.totalRegistrants, 10) + (self.guests.length - self.initialGuestsCount);
2553									self.options.totalRegistrants = totalRegistrants;
2554									reservation.attr('data-total-registrants', totalRegistrants);
2555									self.initialGuestsCount = self.guests.length;
2556								} else {
2557									alert(json.message);
2558								}
2559							});
2560						}).appendTo(footer);
2561					}
2562
2563					var row = $('<div class="row"></div>').appendTo(stage);
2564					var left = $('<div class="col-sm-6"></div>').appendTo(row);
2565					self.right = $('<div class="col-sm-6"></div>').appendTo(row);
2566					$('<div></div>').text('Guest registrants').appendTo(self.right);
2567					$('<ul class="events2-more-people-list"></ul>').appendTo(self.right);
2568
2569					var person = $('<div class="form-horizontal">');
2570					var firstName = $('<div class="form-group">' +
2571						'<label for="first_name" class="col-sm-5 control-label">First name <span class="required-field"></span></label>' +
2572						'<div class="col-sm-7">' +
2573						'<input type="email" class="form-control" id="first_name">' +
2574						'</div>' +
2575						'</div>');
2576
2577					var lastName = $('<div class="form-group">' +
2578						'<label for="last_name" class="col-sm-5 control-label">Last name</label>' +
2579						'<div class="col-sm-7">' +
2580						'<input type="email" class="form-control" id="last_name">' +
2581						'</div>' +
2582						'</div>');
2583
2584					var ageSelect = $('<div class="form-group">' +
2585						'<label for="age" class="col-sm-5 control-label">Age <span class="required-field"></span></label>' +
2586						'<div class="col-sm-7">' +
2587						'<select class="form-control" id="age">' +
2588						'</select>' +
2589						'</div>');
2590
2591					var add = $('<div class="ammev-add-guest"><button class="btn btn-info">add</button></div>');
2592					person.append(firstName).append(lastName);
2593					if (+self.options.enableAgeGroups === 1) {
2594						person.append(ageSelect);
2595					}
2596					person.append(add);
2597					if (+self.options.enableBilling === 0 && +self.options.enableMultipleTypes === 0) {
2598						$('<div></div>').text('Add a guest').appendTo(left);
2599						person.appendTo(left);
2600					}
2601
2602					$.getJSON(self.apiServer + '/v1/' + self.keyword + '/eventsages', { type: 'singular' }, function (json, textStatus) {
2603						$select = $('#age', left).empty().append('<option value="">Select age group</option>');
2604						$.each(json, function (index, val) {
2605							$('<option>' + val.name + '</option>').appendTo($select);
2606						});
2607
2608					});
2609
2610
2611					popup.on('click', '.events2-more-people-list .btn', function (event) {
2612						event.preventDefault();
2613						var gi = $(this).closest('li').index();
2614						self.guests.splice(gi, 1);
2615
2616						if (typeof self.tickets !== 'undefined') {
2617							for (var t = 0; t < self.tickets.length; t++) {
2618								if (self.tickets[t].id === 'g' + gi) {
2619									var removed = self.tickets.splice(t, 1);
2620									// We need to update the available counts in ticketInfo
2621									updateTicketData(removed, self.details.ticketInfo, self.enableBilling, self.details.recurring_id, self.screens.regForm, 1, 'add');
2622									refreshTicketList();
2623									break;
2624								}
2625							}
2626						}
2627
2628						renderList();
2629					}).on('click', '.ammev-add-guest .btn', function (event) {
2630						event.preventDefault();
2631
2632						//max guests is incorrectly named, this should include the user that registered for the event
2633						//in the control panel maxGuests is named 'Limit seats per registration'
2634						//booking specific seat limit
2635						var booking_registrationSeatCount = (/* the patron that registered */ 1) + self.guests.length;
2636						var booking_maxRegistrationSeatLimit = parseInt(self.options.maxGuests, 10);
2637
2638						//Total registrants is not accurate once guests have been added or removed in this booking
2639						var total_currentEventRegistrants = parseInt(self.options.totalRegistrants, 10) - self.initialGuestsCount + self.guests.length;
2640						var total_maxEventAttendees = parseInt(self.options.maxAttendee, 10);
2641
2642						//seats available to the patron for booking
2643						var booking_availableSeats = booking_maxRegistrationSeatLimit - booking_registrationSeatCount;
2644						var total_availableSeatsForEvent = total_maxEventAttendees - total_currentEventRegistrants;
2645
2646						if (total_availableSeatsForEvent < 1) {
2647							var n = total_maxEventAttendees - total_currentEventRegistrants;
2648							switch (n) {
2649								case 0:
2650									alert('Sorry there are no seats left for this event. You cannot add any more registrants.');
2651									break;
2652								case 1:
2653									alert('Sorry there is only 1 seat left for this event. You cannot add any more registrants.');
2654									break;
2655								default:
2656									alert('Sorry there are only ' + n + ' seats left for this event. You cannot add any more registrants.');
2657									break;
2658							}
2659							return;
2660						}
2661
2662						if (booking_maxRegistrationSeatLimit > 0 && booking_availableSeats < 1) {
2663							alert('Sorry, we were unable to add this guest. There is a limit of ' + booking_maxRegistrationSeatLimit + ' seats per registration for this event.');
2664							return;
2665						}
2666
2667						var age = (+self.options.enableAgeGroups === 1) ? $('#age', person).val() : '';
2668						var first_name = $('#first_name', person).val();
2669						var last_name = $('#last_name', person).val();
2670						var ticketName = '';
2671						var ticketType = 0;
2672
2673						if (typeof details !== 'undefined' && details.ticketInfo) {
2674							ticketType = parseInt($('#ticket-dd', person).attr('data-typeid'));
2675							ticketName = $('#ticket-dd :selected', person).text();
2676							ticketCost = parseFloat($('#ticket-dd > option:selected', person).attr('data-cost'));
2677						}
2678
2679						if (first_name.length > 0) {
2680							var guestData = { first_name: first_name, last_name: last_name, age: age };
2681							if (ticketType > 0) {
2682								guestData.ticketType = ticketType;
2683								guestData.ticketName = ticketName;
2684								guestData.ticketCost = ticketCost;
2685								self.tickets.push({ cost: ticketCost, type: ticketType, name: ticketName, id: 'guest-' + self.guests.length });
2686							}
2687
2688							self.guests.push(guestData);
2689							$('#age', person).val('');
2690							$('#first_name', person).val('');
2691							$('#last_name', person).val('');
2692							renderList();
2693						} else {
2694							footer.find('.events2-error-message').text('Please enter information for all required fields').fadeIn().delay(3000).fadeOut();
2695							if (first_name.length === 0) $('#first_name', person).addClass("hightlight-field").delay(3000).queue(function () {
2696								$(this).removeClass("hightlight-field").dequeue();
2697							});
2698							if (age.length === 0) $('#age', person).addClass("hightlight-field").delay(3000).queue(function () {
2699								$(this).removeClass("hightlight-field").dequeue();
2700							});
2701						}
2702					});
2703					renderList();
2704					popup.data('plugin_amPopup').open();
2705
2706				});
2707			});
2708			function renderList() {
2709				var list = $('.events2-more-people-list', self.right).empty();
2710
2711				$.each(self.guests, function (index, val) {
2712					var guestLine = $('<li />');
2713					var gBtn = $('<div class="btn btn-default"><i class="fa fa-times"></i></div>');
2714					var gAge = $('<div><i>
2714' + val.age + '</i></div>');
2715					var gTicket = '';
2716
2717					if (+self.options.enableBilling === 1 || +self.options.enableMultipleTypes === 1) {
2718						guestLine.append(val.first_name + ' ' + val.last_name);
2719					} else {
2720						guestLine.append(gBtn).append(val.first_name + ' ' + val.last_name);
2721					}
2722
2723
2724					if ((typeof self.eventSettings !== 'undefined' && self.eventSettings.events_age_enabled) || val.age !== '') {
2725						guestLine.append(gAge);
2726					}
2727
2728					if (val.ticketType) {
2729						gTicket = $('<div><i class="fa fa-ticket"></i>&nbsp;&nbsp;<i>' + val.ticketType + '</i></div>');
2730						guestLine.append(gTicket);
2731					}
2732
2733					guestLine.appendTo(list);
2734				});
2735			}
2736
2737		}
2738	});
2739	return this;
2740};
2741
2742function polarisFindACopy(book_id, lat, lng) {
2743	var client = $('meta[name=client]').attr('content');
2744	var apiserver = $('meta[name=apiserver]').attr('content') || 'https://api.communico.co';
2745
2746	$.get(apiserver + '/v1/' + client + '/polaris/bibgetholdings/' + book_id, function (data) {
2747		if (data.result === 'ok' && data.data.BibHoldingsGetRows.length > 0) {
2748			var $data = $('<div class="fluid-container"/>');
2749			var $row = $('<div class="row"/>').appendTo($data);
2750			$('<div class="fc-details polaris-book col-sm-12"/>').appendTo($row);
2751			$('<div class="fc-map col-sm-6"/>').append('<div id="map-canvas" class="copies-map"></div>').appendTo($row);
2752			$('<div class="fc-list col-sm-6"/>').append('<h4>Available in these branches now</h4>').appendTo($row);
2753			var $table = $('<table class="polaris-copies-table"/>').appendTo($('.fc-list', $data));
2754
2755			// $('div[data-book='+book_id+']').clone().appendTo($('.fc-details', $data));
2756			// $('.find-button', $data).remove();
2757			// $('.summary', $data).remove();
2758
2759			var mapOptions = {
2760				center: new google.maps.LatLng(lat, lng),
2761				zoom: 9
2762			};
2763			var $popupwidget = showPopupWidget('Find a copy', $data);
2764
2765			$.get(apiserver + '/v1/' + client + '/polaris/bibget/' + book_id, function (data) {
2766				if (data.result === 'ok') {
2767					var itemdetails = {};
2768					$.each(data.data.BibGetRows, function (index, val) {
2769						itemdetails[val.Label.trim().slice(0, -1)] = val.Value.trim();
2770					});
2771					if (itemdetails['ISBN'] && itemdetails['ISBN'].length > 0) {
2772						itemdetails['ISBN'] = itemdetails['ISBN'].match(/\d+/)[0];
2773						$('<div class="cover"><img class="polaris-list-image" onload="coverLoaded(this)" src="http://www.syndetics.com/index.aspx?isbn=' + itemdetails['ISBN'] + '/SC.GIF&amp;client=monpolusg"></div>').appendTo($('.fc-details', $data));
2774					} else {
2775						$('<div class="cover"><img class="polaris-list-image" src="http://placehold.it/75x100"></div>').appendTo($('.fc-details', $data));
2776					}
2777					var $info = $('<div class="clearfix"></div>').appendTo($('.fc-details', $data));
2778					$('<div class="title headingtext">' + itemdetails['Title'] + '</div>').appendTo($info);
2779					$('<div class="author"><span class="polaris-profile-title">By</span> ' + itemdetails['Author'] + '</div>').appendTo($info);
2780					$('<div class="publisher"><span class="polaris-profile-title">Publisher, date</span> ' + itemdetails['Publisher, Date'] + '</div>').appendTo($info);
2781					var formatClass = getFormatClassFromName(itemdetails['Format']);
2782					$('<div class="format"><span class="polaris-profile-title">Format</span> <i class="' + formatClass + '"></i> ' + itemdetails['Format'] + '</div>').appendTo($info);
2783
2784					var $btns = $('<div class="book-buttons"></div>').appendTo($('.fc-details', $data));
2785					$('<button class="button" disabled="disabled">Reserve</button>').appendTo($btns);
2786					$('<span class="polaris-profile-title">&nbsp; ' + itemdetails['System Items Available'] + ' of ' + itemdetails['System Availability'] + ' available</span>').appendTo($btns);
2787				}
2788			});
2789
2790			setTimeout(function () {
2791				var map = new google.maps.Map(document.getElementById("map-canvas"), mapOptions);
2792				var done = [];
2793				$.each(data.data.BibHoldingsGetRows, function (index, val) {
2794					if (done.indexOf(val.LocationID) === -1) {
2795						done.push(val.LocationID);
2796						if (val.ItemsIn > 0) {
2797							$table.append('<tr><td><a target="_blank" class="location-link">' + val.LocationName + '</a></td><td class="polaris-copies-total">' + val.ItemsIn + ' of ' + val.ItemsTotal + '</td></tr>');
2798						}
2799						if (val.location && val.ItemsIn > 0) {
2800							var position = new google.maps.LatLng(val.location.lat, val.location.lon);
2801
2802							var marker = new google.maps.Marker({
2803								position: position,
2804								map: map,
2805								title: val.LocationName
2806							});
2807
2808							var iw = new google.maps.InfoWindow({
2809								content: val.LocationName + ', ' + val.ItemsIn + ' available',
2810								maxWidth: 300
2811							});
2812							google.maps.event.addListener(marker, 'mouseover', function () {
2813								iw.open(map, this);
2814							});
2815
2816							google.maps.event.addListener(marker, 'mouseout', function () {
2817								iw.close();
2818							});
2819						}
2820						$.get(apiserver + '/v1/' + client + '/locations', function (data) {
2821							var locations = {};
2822							$.each(data, function (index, val) {
2823								locations[val.evanced_name] = val;
2824							});
2825							$('.location-link', $table).each(function () {
2826								$(this).attr('href', locations[$(this).text()].about_url);
2827							});
2828						});
2829
2830					}
2831				});
2832
2833			}, 500);
2834
2835		} else {
2836			alert('Sorry this item is currently unavailable');
2837		}
2838	});
2839}
2840$.fn.amSearchBox = function (options) {
2841	this.each(function (index, el) {
2842		var self = $(this);
2843		if (!self.data('amSearchBox')) {
2844			self.data('amSearchBox', true);
2845			self.options = $.extend({}, $.fn.amSearchBox.defaults, options);
2846			self.element = el;
2847			self.$element = $(el);
2848			var showText = function (target, message, index, interval) {
2849				if (index < message.length) {
2850					$(target).append(message[index++]);
2851					setTimeout(function () { showText(target, message, index, interval); }, interval);
2852				}
2853			}
2854		}
2855	});
2856	return this;
2857};
2858$.fn.amAdvancedSlideshow = function (options) {
2859	this.each(function (index, el) {
2860		var self = $(this);
2861		if (!self.data('amAdvancedSlideshow')) {
2862			self.data('amAdvancedSlideshow', true);
2863			self.options = $.extend({}, $.fn.amAdvancedSlideshow.defaults, options);
2864			self.element = el;
2865			self.$element = $(el);
2866			self.$element.find('[data-style]').each(function (index, el) {
2867				$(this).css($.parseJSON($(this).attr('data-style')));
2868			});
2869			$('.advanced-slideshow', self.element).show().cycle();
2870		}
2871	});
2872	return this;
2873};
2874
2875$.fn.amEVWidget = function (options) {
2876	this.each(function (index, el) {
2877		var self = $(this);
2878		if (!self.data('amEVWidget')) {
2879			self.data('amEVWidget', true);
2880			self.options = $.extend({}, $.fn.amEVWidget.defaults, options);
2881			self.element = el;
2882			self.$element = $(el);
2883			self.locationID = self.$element.attr('data-location-id');
2884			self.locationName = self.$element.attr('data-location-name');
2885			self.fullWidth = parseInt(self.$element.attr('data-full-width'), 10);
2886			self.popupAll = parseInt(self.$element.attr('data-popup-all'), 10);
2887			self.eventType = self.$element.attr('data-type');
2888			self.eventType = self.$element.attr('data-type');
2889			self.portal = self.$element.attr('data-portal');
2890			self.private = self.$element.attr('data-private');
2891			self.includePrivate = self.$element.attr('data-include-private');
2892			self.featured = self.$element.attr('data-featured');
2893			self.tags = $.parseJSON(self.$element.attr('data-tags')) || [];
2894			self.ages = $.parseJSON(self.$element.attr('data-ages')) || [];
2895			self.searchTags = $.parseJSON(self.$element.attr('data-search-tags')) || [];
2896
2897			var size = 5;
2898			var c = self.$element.closest("div[class*='col-']").attr('class');
2899			if (c) {
2900				size = parseInt(c.match(/col-[\w]*-[0-9]*/g)[0].match(/(\d+)/g)[0], 10);
2901			}
2902			self.$element.addClass('row');
2903			var $cRow = $('<div class="amev-cal-row"></div>').appendTo(self.element);
2904			if (size >= 4 && self.fullWidth === 0) {
2905				self._display = $('<div class="amev-cal-date col-sm-6 linkcolour"></div>').appendTo($cRow);
2906				$('<div class="col-sm-6"><div class="amev-cal-inline"></div></div>').appendTo($cRow);
2907			} else {
2908				self._display = $('<div class="amev-cal-date col-sm-12 linkcolour"></div>').appendTo($cRow);
2909				$('<div class="col-sm-12"><div class="amev-cal-inline"></div></div>').appendTo($cRow);
2910			}
2911			$('<div class="amev-cal-date-title">Events</div>').appendTo(self._display);
2912
2913			var $lRow = $('<div class="amev-list-row"></div>').appendTo(self.element);
2914			self._list = $('<div class="amev-event-list col-sm-12"></div>').appendTo($lRow);
2915
2916			self._date = $('<div class="amev-date headingtext"></div>').appendTo(self._display);
2917			if (self.locationID) {
2918				$('<div class="amev-location"></div>').text(self.locationName).appendTo(self._display);
2919			}
2920			if (self.popupAll === 1) {
2921				$("<div default='all' data-type='" + self.eventType + "' class='amev-all-events-link eeeventall eeventlink link col-sm-12'>See all events</div>").appendTo(self.element);
2922			} else {
2923				$("<div class='amev-all-events-link'><a href='/events'>See all events</a></div>").appendTo(self.element);
2924			}
2925
2926			function updateCalendar(date) {
2927				var m = moment(date);
2928				self._date.text(m.format('MMM DD'));
2929				self._list.empty().append('<div class="amev-message">Loading...</div>');
2930				var req = { date: date };
2931				if (self.locationID) {
2932					req.locations = [self.locationID];
2933				}
2934				req.types = self.tags || false;
2935				req.groups = self.ages || false;
2936				req.searchTags = self.searchTags || false;
2937				req.includePrivate = self.includePrivate || false;
2938				req.private = self.private || false;
2939				req.featured = self.featured || false;
2940
2941				$.getJSON('/eeventcaldata', { event_type: self.eventType, req: JSON.stringify(req) }, function (json, textStatus) {
2942					if (json.length > 0) {
2943						self._list.empty();
2944						$.each(json, function (index, val) {
2945							createEvent(val).appendTo(self._list);
2946						});
2947					} else {
2948						if (self.locationID) {
2949							self._list.empty().append('<div class="amev-message">' + self.locationName + ' has no events for this day</div>');
2950						} else {
2951							self._list.empty().append('<div class="amev-message">No events for this day</div>');
2952						}
2953						if (self.popupAll === 1) {
2954							self._list.append('<div default="all" data-type="' + self.eventType + '" class="linkcolour amev-all-branches"><i class="am-events"></i><span>Check for events at our other branches</div>');
2955						} else {
2956							$("<div class='amev-all-branches'><a href='/" + self.portal + "/events'><i class='am-events'></i><span>Check for events at our other branches</a></div>").appendTo(self._list);
2957						}
2958					}
2959				});
2960			}
2961			self.cal = rome($('.amev-cal-inline', self)[0], {
2962				appendTo: 'parent',
2963				dayFormat: 'D',
2964				styles: { container: 'amev-cal-container widgetbg' },
2965				time: false
2966			}).on('ready', function (value) {
2967				$('.rd-back', self.element).attr('title', 'Previous month');
2968				$('.rd-next', self.element).attr('title', 'Next month');
2969				$('.rd-back', self.element).html('<span class="sr-only">Previous month</span>');
2970				$('.rd-next', self.element).html('<span class="sr-only">Next month</span>');
2971			}).on('data', function (value) {
2972				$('.rd-back', self.element).attr('title', 'Previous month');
2973				$('.rd-next', self.element).attr('title', 'Next month');
2974				$('.rd-back', self.element).html('<span class="sr-only">Previous month</span>');
2975				$('.rd-next', self.element).html('<span class="sr-only">Next month</span>');
2976				updateCalendar(value);
2977			});
2978			self.$element.on('click', '.amev-all-branches', function (event) {
2979				event.preventDefault();
2980				var $me = $(this);
2981				if ($me.attr('open') == 'yes') return;
2982				eEventPopup(this);
2983				return false;
2984			});
2985
2986
2987			updateCalendar(moment().format('YYYY-MM-DD'));
2988
2989			function createEvent(data) {
2990				// console.log(data);
2991				var $e = $('<div class="amev-event"></div>');
2992
2993				// #1408CH, #3346
2994				// Proper fix for event widget showing cancellations - rather than deleting them.
2995
2996				if (data.changed == 3) {
2997					$e.addClass('amev-event-postponed');
2998				}
2999				if (data.changed == 3 || data.changed == 2) {
3000					$e.append($('<div class="eelist-changed-message">Rescheduled</div>'));
3001				} else if (data.changed == 1) {
3002					$e.addClass('amev-event-canceled');
3003					$e.append($('<div class="eelist-changed-message">Cancelled</div>'));
3004				}
3005
3006				if (data.link) {
3007					var link = $('<a target="_top" href="' + data.link + '"> ' + $('<div></div>').html(data.title).text() + '</a>');
3008				} else {
3009					var link = $('<a target="_top" href="/' + self.portal + '/event/' + data.id + '"> ' + data.title + '</a>');
3010				}
3011
3012				if (data.sub_title) {
3013					link.append('<span> - ' + data.sub_title + '</span>');
3014				}
3015
3016				$('<div class="amev-event-title"></div>').append(link).appendTo($e);
3017
3018				$('<div class="amev-event-time headingtext">' + data.time_string + '</div>').appendTo($e);
3019				if (!self.locationID) {
3020					$('<div class="amev-event-location headingtext"><i class="am-locations"></i>' + data.location + '</div>').appendTo($e);
3021				}
3022				if (data.ages) {
3023					$('<div class="amev-event-ages headingtext"><b>AGE GROUP: </b>' + data.ages + '</div>').appendTo($e);
3024				}
3025				$('<div class="amev-event-description"></div>').html(data.description).appendTo($e);
3026				$('<hr>').appendTo($e);
3027				return $e;
3028			}
3029		}
3030	});
3031	return this;
3032};
3033
3034(function ($, window, document, undefined) {
3035	var pluginName = "amPopup",
3036		defaults = {
3037			title: '',
3038			popUpClass: '',
3039			showTitle: true
3040		};
3041	function Plugin(element, options) {
3042		this.element = element;
3043		this.$element = $(element);
3044		this.settings = $.extend({}, defaults, options);
3045		this._defaults = defaults;
3046		this._name = pluginName;
3047		this.refreshOnClose = false;
3048		this.init();
3049	}
3050
3051	$.extend(Plugin.prototype, {
3052		init: function () {
3053			var self = this;
3054
3055			self.cover = $('<div class="amPopupCover"></div>').appendTo('body');
3056
3057			var popupwrapper = (window.popupwrapper || '');
3058			if ('' != popupwrapper) {
3059				self.cover.wrap('<div class="' + popupwrapper + '"></div>')
3060			}
3061
3062			self.popUp = $('<div role="dialog" aria-modal="true" class="amPopup"></div>').addClass(self.settings.popUpClass).appendTo('body').hide();
3063			if ('' != popupwrapper) {
3064				self.popUp.wrap('<div class="' + popupwrapper + '"></div>')
3065			}
3066
3067			if (self.settings.width) {
3068				self.popUp.css('width', self.settings.width);
3069			}
3070			if (self.settings.showTitle) {
3071				self.titleBar = $('<div class="amPopupTitleBar"></div>').appendTo(self.popUp);
3072				$('<button aria-label="close dialog" class="btn btn-default pull-right">&nbsp;<i class="fa fa-times"></i>&nbsp;</button>').appendTo(self.titleBar).on('click', function (event) {
3073					event.preventDefault();
3074					self.close();
3075				});
3076			}
3077			if (self.settings.title) {
3078				$('<span class="amPopupTitle"></span>').text(self.settings.title).appendTo(self.titleBar);
3079				self.popUp.attr('aria-label', self.settings.title);
3080			}
3081
3082			self.content = $('<div class="amPopupContent"></div>').appendTo(self.popUp);
3083
3084		},
3085		setupTabTrap: function () {
3086			var self = this;
3087			var focusableElements = 'button, [href], input, select, textarea, [tabindex]:not([tabindex="-1"])';
3088			var $modal = $(self.popUp);
3089
3090			var focusableContent = $modal
3091				.find('.screen:visible,.events2-reg-footer,.amPopupTitleBar')
3092				.find(focusableElements)
3093				.filter(':visible');
3094
3095			var firstFocusableElement = focusableContent[0]; // get first element to be focused inside modal
3096			var lastFocusableElement = focusableContent[focusableContent.length - 1]; // get last element to be focused inside modal
3097
3098			document.addEventListener('keydown', function (e) {
3099
3100				var isTabPressed = e.key === 'Tab' || e.keyCode === 9;
3101
3102				if (!isTabPressed) {
3103					return;
3104				}
3105
3106				if (e.shiftKey) { // if shift key pressed for shift + tab combination
3107					if (document.activeElement === firstFocusableElement) {
3108						lastFocusableElement.focus();
3108 // add focus for the last focusable element
3109						e.preventDefault();
3110					}
3111				} else { // if tab key is pressed
3112					if (document.activeElement === lastFocusableElement) { // if focused has reached to last focusable element then focus first focusable element after pressing tab
3113						firstFocusableElement.focus(); // add focus for the first focusable element
3114						e.preventDefault();
3115					}
3116				}
3117			});
3118
3119			if (firstFocusableElement) { firstFocusableElement.focus(); }
3120		},
3121		open: function (refreshOnClose) {
3122			var self = this;
3123			self.$element.appendTo(self.content);
3124			self._position();
3125
3126			if (typeof refreshOnClose === 'undefined') {
3127				refreshOnClose = false;
3128			}
3129
3130			self.refreshOnClose = refreshOnClose;
3131			// #2661 - Colin K.
3132			// Fix for popover issue
3133			// Essentially just hide all quick tips on 'click mouseleave'
3134			if ($('.qtip').length > 0) {
3135				$('.qtip').qtip('api').hide();
3136			}
3137
3138			self.popUp.show();
3139			self.setupTabTrap();
3140		},
3141		close: function () {
3142			var self = this;
3143
3144			self.popUp.remove();
3145			self.cover.remove();
3146			//$('.eventRegButton').prop('disabled', false);
3147
3148			if (self.refreshOnClose) {
3149				location.reload(true);
3150			}
3151		},
3152		_position: function () {
3153			var self = this;
3154			// self.popUp.position({
3155			// 	of: $(window)
3156			// });
3157			if (self.popUp.height() + 300 > $(window).height()) {
3158				var pos = ($(window).height() - self.popUp.height()) / 2;
3159				self.popUp.css('top', $(window).scrollTop() + (pos > 0 ? pos : 0) + 'px');
3160			} else {
3161				self.popUp.css('top', $(window).scrollTop() + 300 + 'px');
3162			}
3163		}
3164	});
3165
3166	$.fn[pluginName] = function (options) {
3167		return this.each(function () {
3168			if (!$.data(this, "plugin_" + pluginName)) {
3169				$.data(this, "plugin_" + pluginName, new Plugin(this, options));
3170			}
3171		});
3172	};
3173})(jQuery, window, document);
3174
3175/***********************************start regButton*******************************************/
3176
3177$.fn.regButton = function (options) {
3178	this.each(function (index, el) {
3179		var self = $(this);
3180		$.extend(true, self, $.fn['amShared']);
3181
3182		if (!self.data('regButton')) {
3183			self.data('regButton', true);
3184			self.apiServer = $('meta[name=apiserver]').attr('content') || 'https://api.communico.co';
3185			self.keyword = $('meta[name=client]').attr('content');
3186			self.options = $.extend({}, $.fn.regButton.defaults, options);
3187			self.eventid = $(this).attr('data-eventid');
3188			self.regtype = parseInt($(this).attr('data-regtype'), 10);
3189			self.recurringid = $(this).attr('data-recurringid');
3190			self.attendanceType = $(this).attr('data-attendancetype');
3191			self.registration = null;
3192			self.popup = false;
3193			self.extraDates = [];
3194			self.extraDatesFutureOpenReg = [];
3195			self.stage = '';
3196			self.footer = '';
3197			self.details = null;
3198			self.eventSettings = null;
3199			self.tickets = [];
3200			self.showPayment = false;
3201			self.showOffline = true;
3202			self.ticketTotal = 0.00;
3203			self.screens = {};
3204			self.guests = [];
3205			self.screenPos = 1;
3206			self.isOffline = false;
3207			self.backButton = null;
3208			self.regBtn = null;
3209			self.eventDetails = null;
3210			self.enableBilling = false;
3211			self.enableMultipleTypes = false;
3212			self.selectedDates = [];
3213			self.disableGuestDetails = 0;
3214			self.availablePaymentTypes = [];
3215			self.bookingPaymentType = 'card';
3216			self.ppTestMode = $(this).attr('data-testmode');
3217			self.mayOptForWaitlist = false;
3218			self.excessGuests = 0;
3219			try {
3220				self.PayPalPayFlow = new PayPalPayFlow('S', $(this).attr('data-testmode'), $("meta[name='client']").attr('content'));
3221			} catch (e) {
3222				self.PayPalPayFlow = null;
3223			}
3224
3225			self.on('click', function (event) {
3226				event.preventDefault();
3227				//self.prop('disabled', true);
3228				if (typeof event.originalEvent == "undefined") {
3229					// This window was called via script, not a human button-press
3230					self.attendanceType = 'UNKNOWN';
3231				};
3232				if (inIframe()) {
3233					var currentPathname = window.location.pathname || '';
3234					var registrationParam = null;
3235					var searchMatch = (window.location.search || '').match(/[?&]registration=([^&]+)/);
3236					if (searchMatch) {
3237						registrationParam = decodeURIComponent(searchMatch[1].replace(/\+/g, ' '));
3238					}
3239					try {
3240						var currentUrl = new URL(window.location.href);
3241						currentPathname = currentUrl.pathname;
3242						registrationParam = currentUrl.searchParams.get('registration');
3243					} catch (e) {
3244					}
3245					var isEmbeddedEventRegistrationView = /^\/event\/[^/]+$/.test(currentPathname.replace(/\/+$/, '')) && registrationParam === 'true';
3246					if (isEmbeddedEventRegistrationView) {
3247						$.getJSON(self.apiServer + '/v1/' + self.keyword + '/eventsettings', function (json) {
3248							self.eventSettings = json;
3249							openPopup();
3250						});
3251						return;
3252					}
3253					var registrationPath = '/event/' + encodeURIComponent(self.eventid) + '?registration=true';
3254					var classicEmbeddedPageConfig = window.classicEmbeddedPageConfig;
3255					var canPostEmbeddedNavigation = classicEmbeddedPageConfig && classicEmbeddedPageConfig.enabled && classicEmbeddedPageConfig.parentOrigin;
3256					if (canPostEmbeddedNavigation && classicEmbeddedPageConfig.requireEmbedSource) {
3257						canPostEmbeddedNavigation = /^create-classic-/.test(classicEmbeddedPageConfig.embedSource || '');
3258					}
3259					if (canPostEmbeddedNavigation) {
3260						window.parent.postMessage({
3261							source: classicEmbeddedPageConfig.source || 'classic-attend',
3262							type: 'navigate',
3263							payload: { pathAndQuery: registrationPath }
3264						}, classicEmbeddedPageConfig.parentOrigin);
3265					} else {
3266						window.parent.location.href = registrationPath;
3267					}
3268				} else {
3269					$.getJSON(self.apiServer + '/v1/' + self.keyword + '/eventsettings', function (json) {
3270						self.eventSettings = json;
3271						openPopup();
3272					});
3273				}
3274			});
3275		}
3276		function inIframe() {
3277			try {
3278				return window.self !== window.top;
3279			} catch (e) {
3280				return true;
3281			}
3282		}
3283
3284		function hideScreens() {
3285			var screenCnt = Object.keys(self.screens).length;
3286			if (screenCnt > 0) {
3287				for (var screen in self.screens) {
3288					self.screens[screen].hide();
3289				}
3290			}
3291		}
3292
3293		function checkPayment(payData) {
3294
3295			if (!self._isFormClean($('#reg-screen3'))) {
3296				$('.amnp-error-message', self.screens.paymentScreen).text('Please enter information for all required fields').fadeIn().delay(6000).fadeOut();
3297				updateButtonLoading(false);
3298				return;
3299			}
3300
3301			if (!$.payment.validateCardNumber(payData.card_number)) {
3302				$('.amnp-error-message', self.screens.paymentScreen).text('Invalid card number').fadeIn().delay(6000).fadeOut();
3303				updateButtonLoading(false);
3304				return;
3305			}
3306
3307			if (!$.payment.validateCardExpiry(payData.expiration.month, payData.expiration.year)) {
3308				$('.amnp-error-message', self.screens.paymentScreen).text('Invalid expiration date').fadeIn().delay(6000).fadeOut();
3309				updateButtonLoading(false);
3310				return;
3311			}
3312			if (!$.payment.validateCardCVC(payData.cvc)) {
3313				$('.amnp-error-message', self.screens.paymentScreen).text('Invalid cvc').fadeIn().delay(6000).fadeOut();
3314				updateButtonLoading(false);
3315				return;
3316			}
3317
3318			return true;
3319		}
3320
3321		function saveRegistration(payData) {
3322			if (payData != undefined) {
3323				if (!self.eventSettings.payment_new_method) {
3324					self.registration.payment = payData;
3325				} else {
3326					// PayFlow, do NOT send card details to the backend!
3327					self.registration.payment = { mode: 'card' };
3328				}
3329			}
3330			if (self.registration.payment) {
3331				self.registration.markBookingAsPending = self.eventSettings.payment_new_method && self.registration.payment && self.registration.payment.mode === 'card';
3332			}
3333
3334			if (self.enableMultipleTypes || self.enableBilling) self.registration.tickets = self.tickets;
3335			if (self.disableGuestDetails === 1) {
3336				self.registration.guests = self.guests;
3337			}
3338
3339			self.registration.booking_source = 'WEB_V1';
3340
3341			$.post(self.apiServer + '/v2/registration', { data: JSON.stringify(self.registration) }, function (json, textStatus) {
3342				if (json.result == 'error') {
3343					$('.events2-error-message').text(json.data).fadeIn().delay(3000).fadeOut();
3344					var thanksPopupStage = $('<div class="events2-reg-person-popup">' +
3345						'<div class="events2-reg-thanks-stage">' +
3346						'<div class="events2-reg-thanks-title">Unable to register for event.</div>' +
3347						'<div class="events2-reg-thanks-head">' +
3348						'<div class="events2-reg-thanks-evtitle">' + self.details.title + '</div>' +
3349						'<div class="events2-reg-thanks-evlocation"><i class="fa fa-map-marker"></i>&nbsp;' + self.details.location + '</div>' +
3350						'</div>' +
3351						'<div class="events2-reg-thanks-online">' +
3352						'<div class="events2-reg-thanks-online-title">Error message:</div>' +
3353						'<div>' + json.data + '</div>' +
3354						'<div>You can view and register for other events at:</div>' +
3355						'<div><a href="/events">' + (window.websiteUrl || window.location.hostname) + '/events</a></div>' +
3356						'</div>' +
3357						'</div>' +
3358						'</div>');
3359					updateButtonLoading(false);
3360					thanksPopupStage.appendTo(self.screens.thanksScreen);
3361				} else {
3362					// Label for additional dates.
3363					self.registration = json;
3364
3365					if (payData != undefined) {
3366						if (self.eventSettings.payment_new_method) {
3367							// Start the processing animation, we have everything we want
3368							self.PayPalPayFlow.showProcessingAnimation(self.screens.thanksScreen);
3369							updateButtonLoading(false);
3370							screenNav('thanksScreen');
3371
3372							self.ticketTotal = 0.00;
3373							for (var t = 0; t < self.tickets.length; t++) {
3374								var tkt = self.tickets[t];
3375								self.ticketTotal += parseFloat(tkt.cost);
3376							}
3377
3378							/* the value of CURRENCY seems to be ignored by paypal, we might want to remove the parameter */
3379							var transactionData = {
3380								'AMT': self.ticketTotal.toFixed(2) * (self.selectedDates.length + 1),
3381								'CVV2': payData.cvc,
3382								'EXPDATE': ("0" + payData.expiration.month.toString() + payData.expiration.year.toString().substr(2)).slice(-4),
3383								'ACCT': payData.card_number.replace(/ /g, ''),
3384								'BILLTOFIRSTNAME': payData.first_name,
3385								'BILLTOLASTNAME': payData.last_name,
3386								'EMAIL': payData.email,
3387								'CURRENCY': self.eventSettings.payment_currency
3388							};
3389							var cleanDetails = {
3390								title: self.details.title,
3391								location: self.details.location,
3392								datestring: self.details.datestring,
3393								time_string: self.details.time_string
3394							}
3395							$.post((window.websiteUrl || "") + '/events', { registrationCache: { registrations: json.registrations, registrationId: json.registrationId, extraDates: self.extraDates, master: json.master, ref: json.ref, details: cleanDetails, tickets: json.tickets } }, function (session) {
3396								if (session.id) {
3397									self.PayPalPayFlow.sendEventTransaction(transactionData, session.id, false, false, false);
3398								}
3399								return;
3400							}, 'json');
3401						} else {
3402							// If not new method then payment has already occurred.
3403							var thanksPopupStage = '';
3404							if (json.registrations.length > 0) {
3405								// #3620, 4651, CH#575 - CK
3406								// Fix to display all waitlist registered events
3407								// Additional sorting going on so that we can build two lists if we registered and waitlisted.
3408
3409								// No need to repeat the drawing code anymore, just use the event summary to get the HTML
3410								if (self.PayPalPayFlow === null) {
3411									self.PayPalPayFlow = new PayPalPayFlow('', self.ppTestMode, $("meta[name='client']").attr('content'));
3412								}
3413
3414								var registrationData = { registrations: json.registrations, extraDates: self.extraDates, master: json.master, ref: json.ref, details: self.details };
3415								thanksPopupStage = self.PayPalPayFlow.showEventSummary(registrationData)
3416							}
3417
3418							thanksPopupStage.appendTo(self.screens.thanksScreen);
3419							updateButtonLoading(false);
3420							screenNav('thanksScreen');
3421						}
3422					} else {
3423						// If paydata is null, then behave as normal...
3424						var thanksPopupStage = '';
3425						if (json.registrations.length > 0) {
3426							// #3620, 4651, CH#575 - CK
3427							// Fix to display all waitlist registered events
3428							// Additional sorting going on so that we can build two lists if we registered and waitlisted.
3429
3430							// No need to repeat the drawing code anymore, just use the event summary to get the HTML
3431							if (self.PayPalPayFlow === null) {
3432								self.PayPalPayFlow = new PayPalPayFlow('', self.ppTestMode, $("meta[name='client']").attr('content'));
3433							}
3434
3435							var registrationData = { registrations: json.registrations, extraDates: self.extraDates, master: json.master, ref: json.ref, details: self.details };
3436							thanksPopupStage = self.PayPalPayFlow.showEventSummary(registrationData)
3437						}
3438
3439						thanksPopupStage.appendTo(self.screens.thanksScreen);
3440						updateButtonLoading(false);
3441						screenNav('thanksScreen');
3442					}
3443				}
3444				//reload events in background
3445				$eventsHolder = $('.events-holder');
3446				if ($eventsHolder.length > 0) {
3447					$eventsHolder.data('plugin_amEvents').reload();
3448				}
3449			}, 'json');
3450		}
3451
3452		function screenNav(screen) {
3453			if (typeof screen === 'undefined') return;
3454
3455			hideScreens();
3456			self.screens[screen].show();
3457			self.backButton.hide();
3458
3459			switch (screen) {
3460				case 'thanksScreen':
3461					if (self.isOffline) {
3462						if (+self.enableBilling === 1) {
3463							self.footer.empty()
3464								.append('<div class="row"><div class="col-md-12 amnp-booking-summary-offline-message">' + self.eventSettings.events_offline_payments_message + '</div></div>');
3465						} else {
3466							self.footer.empty()
3467								.append('<div class="row"><div class="col-md-12 amnp-booking-summary-offline-message">Thank you for registering</div></div>');
3468						}
3469					}
3470
3471					resetValues();
3472					self.regBtn.hide();
3473					break;
3474
3475				case 'regForm':
3476					refreshTicketList();
3477					self.screenPos = 1;
3478					updateButtonText(true);
3479					break;
3480
3481				case 'paymentScreen':
3482					refreshTicketList();
3483					self.screenPos = 2;
3484					self.isOffline = false;
3485					self.backButton.show();
3486					updateButtonText(true);
3487					break;
3488
3489				case 'offlineScreen':
3490					refreshTicketList();
3491
3492					if (self.screenPos !== 2) {
3493						self.screenPos = 3;
3494					} else {
3495						self.screenPos = 4;
3496					}
3497
3498					self.isOffline = true;
3499					self.backButton.show();
3500					updateButtonText(true);
3501					break;
3502
3503				case 'payLaterScreen':
3504					refreshTicketList();
3505
3506					self.screenPos = 5; // 4 might be taken by offlineScreen
3507					self.isOffline = true;
3508					self.backButton.show();
3509					updateButtonText(true);
3510					break;
3511			}
3512
3513			self.popup.data('plugin_amPopup').setupTabTrap();
3514		}
3515
3516		function calculateTickets() {
3517			var totalTickets = 0;
3518			var noTicketsAllocated = true;
3519			self.tickets = [];
3520			self.guests = [];
3521
3522			$('.list-ticket-qty-dd').each(function () {
3523				var typeid = parseInt($(this).attr('data-typeid'));
3524				var limit = parseInt($(this).attr('data-limit'));
3525				var left = parseInt($(this).attr('data-left'));
3526				var cost = $(this).attr('data-cost');
3527				var type = $(this).attr('data-type');
3528				var qty = parseInt($(this).val());
3529
3530				if (qty > 0) {
3531					noTicketsAllocated = false;
3532					totalTickets += qty;
3533				}
3534
3535				if (totalTickets > limit && limit > 0) {
3536					self.tickets = [];
3537					self.guests = [];
3538					return false;
3539				} else {
3540
3541					for (var t = 0; t < qty; t++) {
3542						var hasGuests = self.tickets.length > 0;
3543						var id = self.tickets.length === 0 ? 'main' : 'g-' + (self.tickets.length - 1).toString();
3544
3545						if (hasGuests) {
3546							var guestData = { first_name: 'Guest', last_name: (self.guests.length + 1), age: 0, id: id };
3547							guestData.ticketType = typeid;
3548							guestData.ticketName = name;
3549							guestData.ticketCost = cost;
3550							self.guests.push(guestData);
3551						}
3552
3553						self.tickets.push({
3554							type: typeid,
3555							cost: cost,
3556							name: type,
3557							id: id
3558						});
3559					}
3560				}
3561			});
3562
3563			if (self.tickets.length > 0) {
3564				refreshTicketList();
3565				return true;
3566			}
3567
3568			if(noTicketsAllocated) {
3569				refreshTicketList();
3570			}
3571			return noTicketsAllocated;
3572		}
3573
3574		function refreshTicketList() {
3575			if ($('.amnp-ticket-details', self.screens.regForm).length > 0) $('.amnp-ticket-details', self.screens.regForm).remove();
3576			if ($('.amnp-ticket-details', self.screens.paymentScreen).length > 0) $('.amnp-ticket-details', self.screens.paymentScreen).remove();
3577			if ($('.amnp-ticket-details', self.screens.offlineScreen).length > 0) $('.amnp-ticket-details', self.screens.offlineScreen).remove();
3578			if ($('.amnp-ticket-details', self.screens.payLaterScreen).length > 0) $('.amnp-ticket-details', self.screens.payLaterScreen).remove();
3579			if (self.tickets.length > 0) {
3580				var dateMod = 1;
3581				var wholeOnly = false;
3582				if (self.details) {
3583					if (self.details.whole_serires_only) {
3584						wholeOnly = parseInt(self.details.whole_serires_only, 10) == 1;
3585					}
3586				}
3587
3588				// Check selected date length and add one for the current date you are registering for
3589				var sdl = self.selectedDates.length + 1;
3590				if (sdl > 1) {
3591					dateMod = sdl;
3592				}
3593				var coTicketList = new EventBillingTicketList(self.tickets, dateMod, wholeOnly, parseInt(self.details.enable_billing) === 1, self.eventSettings.payment_currency_symbol).list;
3594				$('.events2-reg-details', self.screens.regForm).after(coTicketList);
3595			}
3596		}
3597
3598		function resetValues() {
3599			self.registration = null;
3600			self.enableMultipleTypes = false;
3601			self.enableBilling = false;
3602			self.showPayment = false;
3603			self.showOffline = true;
3604			self.ticketTotal = 0.00;
3605			self.screenPos = 1;
3606			self.isOffline = false;
3607			self.availablePaymentTypes = [];
3608			self.bookingPaymentType = 'card';
3609		}
3610
3611		function updateButtonText(visible) {
3612			switch (self.screenPos) {
3613				case 1:
3614					self.regBtn.text('Next');
3615
3616					if (!self.showPayment && self.showOffline) {
3617						if (self.regtype == 1 && self.excessGuests == 0) {
3618							self.regBtn.text('Register');
3619						} else {
3620							self.regBtn.text('Join the waitlist');
3621						}
3622					}
3623					break;
3624
3625				case 2:
3626				case 3:
3627				case 4:
3628				case 5:
3629					self.regBtn.addClass('btn-success').removeClass('btn-primary');
3630					if (!self.isOffline && self.bookingPaymentType === 'card') {
3631						self.regBtn.text('Pay');
3632					} else {
3633						self.regBtn.text('Register');
3634					}
3635					break;
3636			}
3637
3638			if (!visible) {
3639				self.regBtn.hide();
3640			} else {
3641				if (!self.regBtn.is(":visible")) {
3642					self.regBtn.show();
3643				}
3644			}
3645		}
3646
3647		function updateButtonLoading(on) {
3648			if (on) {
3649				self.regBtn.prop('disabled', 'disabled');
3650				self.regBtn.append($('<i class="fa fa-circle-o-notch fa-spin"></i>'));
3651			} else {
3652				self.regBtn.removeProp('disabled');
3653				$('.fa-spin', self.regBtn).remove();
3654			}
3655
3656			updateButtonText(true);
3657		}
3658
3659		function ticketDropdownEvent(context) {
3660			var s = $('#ticket-dd :selected', context).val();
3661			if (s !== '') {
3662				var ticket = {
3663					type: parseInt($('#ticket-dd > option:selected', context).attr('data-typeid')),
3664					cost: parseFloat($('#ticket-dd > option:selected', context).attr('data-cost')),
3665					name: $('#ticket-dd > option:selected', context).text(),
3666					id: 'main'
3667				};
3668
3669				var found = 0;
3670				if (typeof self.tickets === 'undefined') return;
3671				if (self.tickets.length > 0) {
3672					for (var t = 0; t < self.tickets.length; t++) {
3673						var tkt = self.tickets[t];
3674						if (typeof tkt.id !== 'undefined') {
3675							if (tkt.id === 'main') {
3676								// If the types don't match then we need to do two things:
3677								// 1. Increase the tickets available for the previous type selected by 1
3678								// 2. Overwrite the ticket stored for saving.
3679								if (tkt.type !== ticket.type) {
3680									// This shouldn't ever happen, but we want to check, jic.
3681									if (typeof self.details.ticketInfo === 'undefined' && typeof self.details.ticketData === 'undefined') return;
3682
3683									// Find the previously saved type within ticket info
3684									var typeIdx = self.details.ticketInfo.ticketData.findIndex(
3685										function (ticketData) {
3686											return parseInt(ticketData.typeId) === parseInt(tkt.type)
3687										}
3688									);
3689
3690									// We found it.
3691									if (typeIdx >= 0) {
3692										self.details.ticketInfo.ticketData[typeIdx].available++;
3693									}
3694
3695									self.tickets[t] = ticket;
3696								}
3697
3698								found = 1;
3699								break;
3700							}
3701						}
3702					}
3703				}
3704
3705				if (!found) {
3706					self.tickets.push(ticket);
3707				}
3708
3709				if (typeof self.details !== 'undefined' && typeof self.details.ticketInfo !== 'undefined' && typeof self.details.recurring_id !== 'undefined') {
3710					drawEventBillingDropDown(self.details.ticketInfo, [ticket], self.enableBilling, self.details.recurring_id, context, 0, 1, 0);
3711				}
3712
3713				refreshTicketList();
3714			}
3715		}
3716
3717		function updateTicketData(ticket, ticketInfo, enableBilling, dateId, context, isGuest, type, updateOnly) {
3718			if (typeof type === 'undefined') var type = 'add';
3719			if (typeof ticketInfo !== 'undefined' && typeof ticketInfo.ticketData !== 'undefined') {
3720				// Then there is class/ticketdata info
3721				var tkt = ticket[0];
3722				var ti = ticketInfo;
3723				var td = Array.isArray(ti.ticketData) && ti.ticketData.length > 0 ? ti.ticketData : [];
3724
3725				var typeIdx = td.findIndex(
3726					function (ticketData) {
3727						return parseInt(ticketData.typeId) === parseInt(tkt.type)
3728					}
3729				);
3730
3731				if (typeIdx >= 0) {
3732					if (type === 'add') {
3733						td[typeIdx].available++;
3734					} else {
3735						td[typeIdx].available--;
3736					}
3737					if (td[typeIdx].available < 0) td[typeIdx].available = 0;
3738					ti.ticketData[typeIdx] = td[typeIdx];
3739				}
3740
3741				ticketInfo = ti;
3742			}
3743
3744			if (updateOnly) {
3745				drawEventBillingDropDown(ticketInfo, [ticket], enableBilling, dateId, context, 0, 0, 0);
3746				return ticketInfo;
3747			}
3748
3749			return;
3750		}
3751
3752
3753		function drawEventBillingDropDown(ticketInfo, tickets, enableBilling, dateId, context, guestPopup, updateCount, adjusted) {
3754			// Ticket dd for guests
3755			var coEventBillingDD = null;
3756			if (typeof ticketInfo !== 'undefined' && typeof ticketInfo.ticketData !== 'undefined') {
3757				// Then there is class/ticketdata info
3758				var ti = ticketInfo;
3759				var td = Array.isArray(ti.ticketData) && ti.ticketData.length > 0 ? ti.ticketData : [];
3760
3761				if (updateCount && !adjusted) {
3762					// Have to add a check to exlude the ticket already selected by the registrant.
3763					if (Array.isArray(tickets) && tickets.length > 0) {
3764						// We want to do this for each ticket, including guests.
3765						for (var t = 0; t < tickets.length; t++) {
3766							var ticket = tickets[t];
3767							var typeIdx = td.findIndex(function (ticketData) { return parseInt(ticketData.typeId) === parseInt(ticket.type) });
3768
3769							if (typeIdx >= 0) {
3770								td[typeIdx].available--;
3771
3772								if (td[typeIdx].available < 0) td[typeIdx].available = 0;
3773								ti.ticketData[typeIdx] = td[typeIdx];
3774							}
3775						}
3776					}
3777				}
3778
3779				if (guestPopup) {
3780					coEventBillingDD = new EventBillingDropdown(dateId, 1, ti, enableBilling).dropdown;
3781					coEventBillingDD.appendTo(context);
3782				} else {
3783					coEventBillingDD = new EventBillingDropdown(dateId, 1, ti, enableBilling).dropdown;
3784					coEventBillingDD.appendTo(context);
3785
3786					if ($("#ticket-dd", context).length > 0) {
3787						var v = $("#ticket-dd :selected", context).val();
3788						var trow = $("#ticket-dd", context).closest('.row').prev();
3789						$("#ticket-dd", context).closest('.row').remove();
3790						trow.after(coEventBillingDD);
3791
3792						if (v !== '') {
3793							$("#ticket-dd", context).val(v);
3794						}
3795
3796						$('#ticket-dd', context).on('change', function () {
3797							ticketDropdownEvent(context);
3798						});
3799					}
3800				}
3801			}
3802		}
3803
3804		function openPopup() {
3805			var website = (window.websiteUrl || "");
3806			$.getJSON(website + '/eventdetails', { eventid: self.eventid }, function (details, textStatus) {
3807				self.details = details;
3808				self.patron = self.details.patron;
3809				self.guests = [];
3810				self.screenPos = 1;
3811				self.disableGuestDetails = parseInt(details.disable_guest_details);
3812
3813				// Set 'force' to a var
3814				var force = parseInt(details.force_series_registration, 10) == 1;
3815				var whole = parseInt(details.whole_serires_only, 10) == 1;
3816				var allowWaitlist = parseInt(details.allow_waitlist, 10) == 1;
3817				var limitWaitlist = self.eventSettings.events_limit_waitlist;
3818				var maxWaitlist = parseInt(details.max_waitlist);
3819				var totalWaitlist = parseInt(details.total_waitlist);
3820				var waitlistClosed = limitWaitlist && (totalWaitlist >= maxWaitlist && maxWaitlist > 0);
3821				// Age Restrictions - CK
3822				var age_min = parseInt(details.age_restriction_min);
3823				var age_max = parseInt(details.age_restriction_max);
3824				var seat_limit = parseInt(details.seat_limit, 10);
3825				var age_restriction = (age_min > 0 || age_max > 0) ? true : false;
3826				var coEventBillingDD = null;
3827				var ticket = {};
3828
3829				// Whole-series-only events stop accepting new registrations once the
3830				// first session has begun. Not every surface that renders a register
3831				// button checks this, so enforce it here where every attempt funnels.
3832				if (parseInt(details.series_registration_closed, 10) === 1) {
3833					alert('Sorry, registration for this event series is now closed.');
3834					return;
3835				}
3836
3837				self.personPopup = false;
3838				self.popup = $('<div class="events2-reg-popup"></div>').amPopup({ title: details.title });
3839				self.stage = $('<div class="events2-reg-stage"></div>').appendTo(self.popup);
3840				self.footer = $('<div class="events2-reg-footer"></div>').appendTo(self.popup);
3841				self.screens = {
3842					errForm: $('<div class="screen" id="reg-screen1"></div>').appendTo(self.stage),
3843					regForm: $('<div class="screen" id="reg-screen2"></div>').appendTo(self.stage).hide(),
3844					paymentScreen: $('<div class="screen" id="reg-screen3"></div>').appendTo(self.stage).hide(),
3845					paymentError: $('<div class="screen" id="reg-screen4"></div>').appendTo(self.stage).hide(),
3846					thanksScreen: $('<div class="screen" id="reg-screen5"></div>').appendTo(self.stage).hide(),
3847					offlineScreen: $('<div class="screen" id="reg-screen6"></div>').appendTo(self.stage).hide(),
3848					payLaterScreen: $('<div class="screen" id="reg-screen7"></div>').appendTo(self.stage).hide(),
3849				};
3850
3851
3852				self.mainTicketAdjusted = false;
3853				self.tickets = [];
3854				self.ticketTotal = 0.00;
3855				self.enableMultipleTypes = typeof details.enable_multiple_types !== 'undefined' && typeof details.ticketInfo !== 'undefined' && typeof details.ticketInfo.ticketData !== 'undefined' ? parseInt(details.enable_multiple_types) : 0;
3856				self.enableBilling = typeof details.enable_billing !== 'undefined' ? parseInt(details.enable_billing) : 0;
3857				self.showOffline = true;
3858				self.showPayment = false;
3859				self.showSMSPrompt = details.allow_sms_optout;
3860				self.SMSOptMode = details.sms_opt_mode;
3861				self.SMSPromptMessage = details.sms_optout_message;
3862
3863				self.PayPalPayFlow = null;
3864				self.backButton = $('<button class="btn btn-edit btn-back amnp-booking-summary-buttons">Back</button>').appendTo(self.footer);
3865				self.backButton.on('click', function () {
3866					switch (self.screenPos) {
3867						case 2: //cardScreen
3868						case 3: //offlineScreen
3869						case 5: //payLaterScreen
3870							screenNav('regForm');
3871							updateButtonText(true);
3872							break;
3873
3874						case 4: //offlineScreen occasionally??
3875							screenNav('paymentScreen');
3876							updateButtonText(true);
3877							break;
3878
3879						default: break;
3880					}
3881				});
3882
3883				self.backButton.hide();
3884
3885				if (details.guests_allowed === null) {
3886					details.guests_allowed = self.eventSettings.events_patron_guests_default;
3887				} else {
3888					details.guests_allowed = parseInt(details.guests_allowed, 10) === 1;
3889				}
3890
3891				if (details.login_required === null) {
3892					details.login_required = self.eventSettings.events_login_required_default;
3893				} else {
3894					details.login_required = parseInt(details.login_required, 10) === 1;
3895				}
3896
3897				if (self.regtype == 1 && parseInt(details.total_registrants, 10) >= parseInt(details.max_attendee, 10)) {
3898					alert('Sorry this event is now full, a wait list may be available.');
3899					if (typeof self.popup.data('plugin_amPopup') !== 'undefined') {
3900						self.popup.data('plugin_amPopup').close();
3901					}
3902
3903					return;
3904				}
3905
3906				self.regBtn = $('<button data-loading-text="<i class=\'fa fa-circle-o-notch fa-spin\'></i>" class="btn btn-default reg-btn amnp-booking-summary-buttons">next</button>').on('click', function (event) {
3907					//self.regBtn.button('loading');
3908					updateButtonLoading(true);
3909					event.preventDefault();
3910					switch (self.screenPos) {
3911						case 1:
3912							var form = $(this).closest('.events2-reg-popup').find('.events2-reg-form');
3913
3914							if (self.disableGuestDetails === 1 && +self.enableMultipleTypes === 1) {
3915								calculateTickets();
3916							}
3917
3918							var data = {
3919								additional_dates: [],
3920								eventid: self.eventid,
3921								first_name: $('#first_name', form).val().trim(),
3922								last_name: $('#last_name', form).val().trim(),
3923								email: $('#email', form).val().trim(),
3924								phone: $('#phone', form).val().trim(),
3925								allow_sms: $('#allow_sms', form).length > 0 ? $('#allow_sms', form).is(":checked") : 0,
3926								age: self.eventSettings.events_age_enabled ? $('#age', form).val() : null,
3927								librarycard: $('#librarycard', form).val().trim(),
3928								others: self.guests,
3929								regtype: self.regtype,
3930								attendanceType: ((self.attendanceType == undefined || self.attendanceType == 'UNKNOWN') ? $('#attendance', form).val() : self.attendanceType),
3931								custom_questions: {}
3932							}
3933
3934							var seats = parseInt(details.max_attendee, 10);
3935							var total = parseInt(details.total_registrants, 10);
3936
3937							if (limitWaitlist) {
3938								var gl = self.guests.length;
3939								var left = 0;
3940
3941								if (seats > 0) {
3942									left = seats - total;
3943								}
3944
3945								if ((left - (gl + 1)) < 0) {
3946									left = 0;
3947									data.regtype = 2;
3948								}
3949
3950								var theoreticalWaitlist = gl + totalWaitlist + (parseInt(data.regtype) === 2 ? 1 : 0) - left;
3951
3952								if (maxWaitlist > 0 && theoreticalWaitlist > maxWaitlist) {
3953									var over = theoreticalWaitlist - maxWaitlist;
3954									$(this).closest('.events2-reg-popup').find('.events2-error-message').text('Unable to register, maximum wait list size will be exceeded. Remove ' + over + ' guest(s) to continue, or cancel registration.').fadeIn().delay(3000).fadeOut();
3955									updateButtonLoading(false);
3956									return;
3957								}
3958							}
3959
3960							if (seat_limit > 0) {
3961								var seatCount = self.guests.length + 1; // Add 1 for the registrant
3962								if (seatCount > seat_limit) {
3963									$(this).closest('.events2-reg-popup').find('.events2-error-message').text('Event has a registration limit of ' + seat_limit + ' seats. To continue, reduce number of registrants to limit.').fadeIn().delay(3000).fadeOut();
3964									updateButtonLoading(false);
3965									return;
3966								}
3967							}
3968
3969							var clean = true;
3970							var registrationType = $(this).closest('.events2-reg-popup').find('.ticket-list');
3971							if(registrationType.length > 0) {
3972								var regType = registrationType.data('regType');
3973								clean = regType.hasSelection();
3974								if(!clean) {
3975									regType.highlightFields();
3976								}
3977							}
3978
3979							if (!self._isFormClean(self.customQuestions) || !self._isFormClean(self.Questions)) {
3980								clean = false;
3981							}
3982
3983							if (!clean) {
3984								$(this).closest('.events2-reg-popup').find('.events2-error-message').text('Please enter information for all required fields').fadeIn().delay(3000).fadeOut();
3985								updateButtonLoading(false);
3986								return;
3987							}
3988
3989							var reemail = /^(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/;
3990							var rephone = new RegExp(self.eventSettings.phone_number_regex, "i");
3991							if (data.first_name.length === 0) {
3992								$(this).closest('.events2-reg-popup').find('.events2-error-message').text('Please enter a first name').fadeIn().delay(3000).fadeOut();
3993								updateButtonLoading(false);
3994								return;
3995							}
3996
3997							if (data.last_name.length === 0) {
3998								$(this).closest('.events2-reg-popup').find('.events2-error-message').text('Please enter a last name').fadeIn().delay(3000).fadeOut();
3999								updateButtonLoading(false);
4000								return;
4001							}
4002
4003							if (!$('#email', form).prop('disabled') && data.email.length > 0 && !reemail.test(data.email)) {
4004								$(this).closest('.events2-reg-popup').find('.events2-error-message').text('Please enter a valid email address').fadeIn().delay(3000).fadeOut();
4005								//self.regBtn.button('reset');
4006								updateButtonLoading(false);
4007								$('#email', form).addClass('amrp-missing-field');
4008								return;
4009							}
4010
4011							if (!$('#phone', form).prop('disabled') && data.phone.length > 0 && !rephone.test(data.phone)) {
4012								$(this).closest('.events2-reg-popup').find('.events2-error-message').text('Please enter a valid phone number').fadeIn().delay(3000).fadeOut();
4013								//self.regBtn.button('reset');
4014								updateButtonLoading(false);
4015								$('#phone', form).addClass('amrp-missing-field');
4016								return;
4017							}
4018
4019							if (details.registration_fields && details.registration_fields.fields) {
4020								for (var i = details.registration_fields.fields.length - 1; i >= 0; i--) {
4021									var field = details.registration_fields.fields[i];
4022									var val = null;
4023									switch (field.type) {
4024										case 'checkbox':
4025											val = $('#' + field.name, self.customQuestions).is(':checked');
4026											break;
4027										default:
4028											val = $('#' + field.name, self.customQuestions).val();
4029											val = val.trim();
4030											break;
4031									}
4032									switch (field.validate) {
4033										case 'custom':
4034											var flags = field.regex.replace(/.*\/([gimy]*)$/, '$1');
4035											var pattern = field.regex.replace(new RegExp('^/(.*?)/' + flags + '$'), '$1');
4036											var regex = new RegExp(pattern, flags);
4037											if (val.length > 0 && !regex.test(val)) {
4038												$(this).closest('.events2-reg-popup').find('.events2-error-message').text('The information entered is not valid').fadeIn().delay(3000).fadeOut();
4039												//self.regBtn.button('reset');
4040												updateButtonLoading(false);
4041												$('#' + field.name, self.customQuestions).addClass('amrp-missing-field');
4042												return;
4043											}
4044											break;
4045										case 'email':
4046											if (val.length > 0 && !reemail.test(val)) {
4047												$(this).closest('.events2-reg-popup').find('.events2-error-message').text('Please enter a valid email address').fadeIn().delay(3000).fadeOut();
4048												//self.regBtn.button('reset');
4049												updateButtonLoading(false);
4050												$('#' + field.name, self.customQuestions).addClass('amrp-missing-field');
4051												return;
4052											}
4053											break;
4054										case 'phone':
4055											if (val.length > 0 && !rephone.test(val)) {
4056												$(this).closest('.events2-reg-popup').find('.events2-error-message').text('Please enter a valid phone number').fadeIn().delay(3000).fadeOut();
4057												//self.regBtn.button('reset');
4058												updateButtonLoading(false);
4059												$('#' + field.name, self.customQuestions).addClass('amrp-missing-field');
4060												return;
4061											}
4062											break;
4063									}
4064									if (null !== val) data.custom_questions[field.name] = val;
4065								}
4066							}
4067
4068							if (self.additionalDates) {
4069								$("input:checked", self.additionalDates).each(function (index, el) {
4070									// Data-waitlist + 1 = regtype. 1 = Reg, 2 = wait.
4071									data.additional_dates.push({ id: $(el).val(), intent: ($(this).attr("data-waitlist") === "true") ? 2 : 1 });
4072								});
4073							}
4074
4075							data.custom_questions = JSON.stringify(data.custom_questions);
4076							self.registration = data;
4077
4078							if (+self.enableBilling === 0) {
4079								saveRegistration();
4080							} else {
4081								//Only possible after coming 'back' from this screen.
4082								updateButtonLoading(false);
4083
4084								if (self.availablePaymentTypes.includes(self.bookingPaymentType)) {
4085									var selectedPayment = paymentTypes.find(function(elem) {
4086										return elem.string == self.bookingPaymentType;
4087									});
4088									screenNav(selectedPayment.screen);
4089									return;
4090								}
4091								// No payment methods available, defaulting to offline
4092								self.isOffline = true;
4093								self.showOffline = true;
4094								self.registration.payment = {
4095									mode: 'offline'
4096								};
4097
4098								saveRegistration();
4099								screenNav('thanksScreen');
4100							}
4101
4102							break;
4103						case 2:
4104							var payData = null;
4105							if (self.showPayment && !self.isOffline) {
4106								self.ticketTotal = 0.00;
4107								for (var t = 0; t < self.tickets.length; t++) {
4108									var tkt = self.tickets[t];
4109									self.ticketTotal += parseFloat(tkt.cost);
4110								}
4111
4112								payData = {
4113									first_name: $('input#card_first_name', self.screens.paymentScreen).val(),
4114									last_name: $('input#card_last_name', self.screens.paymentScreen).val(),
4115									card_number: $('input#card_number', self.screens.paymentScreen).val(),
4116									expiration: $('input#expiration', self.screens.paymentScreen).payment('cardExpiryVal'),
4117									cvc: $('input#CVV2', self.screens.paymentScreen).val(),
4118									amount: self.ticketTotal,
4119									mode: 'card'
4120								}
4121
4122								if (!checkPayment(payData)) {
4123									return;
4124								}
4125							}
4126
4127							saveRegistration(payData);
4128							screenNav('thanksScreen');
4129							break;
4130
4131						// Show the thanks screen
4132						case 3:
4133						case 4:
4134							saveRegistration();
4135							screenNav('thanksScreen');
4136							break;
4137
4138						case 5:
4139							self.registration.payment = {
4140								mode: 'pay_later'
4141							};
4142							saveRegistration();
4143							screenNav('thanksScreen');
4144							break;
4145					}
4146				}).appendTo(self.footer);
4147
4148				function renderList() {
4149					var list = $('.events2-more-people-list', self.screens.regForm).empty();
4150
4151
4152					$.each(self.guests, function (index, val) {
4153						var typeid = (typeof self.guests[index].ticketType !== 'undefined') ? self.guests[index].ticketType : -1;
4154						var guestLine = $('<li />');
4155						var gBtn = $('<div class="btn btn-default" d><i class="fa fa-times"></i></div>');
4156						var gAge = $('<div><i>
4156' + val.age + '</i></div>');
4157						var gTicket = '';
4158
4159						gBtn.on('click', function () {
4160							var tid = $(this).attr('data-typeid');
4161							for (var t = 0; t < self.tickets.length; t++) {
4162								var tkt = self.tickets[t];
4163
4164								if (parseInt(tkt.type) === parseInt(tid)) {
4165									// There is only one...
4166									spliced = true;
4167
4168									var removed = self.tickets.splice(t, 1);
4169									// We need to update the available counts in ticketInfo
4170									updateTicketData(removed, self.details.ticketInfo, self.enableBilling, self.details.recurring_id, self.screens.regForm, 1, 'add');
4171									break;
4172								}
4173							}
4174
4175							refreshTicketList();
4176						});
4177
4178						guestLine.append(gBtn).append(val.first_name + ' ' + val.last_name);
4179
4180						if (self.eventSettings.events_age_enabled) {
4181							guestLine.append(gAge);
4182						}
4183
4184						if (val.ticketTypes) {
4185							gTicket = $('<div><i class="fa fa-ticket"></i>&nbsp;&nbsp;<i>' + val.ticketName + '</i></div>');
4186							guestLine.append(gTicket);
4187						}
4188
4189						guestLine.appendTo(list);
4190					});
4191				}
4192
4193				$('<div class="events2-spacer"><div class="events2-error-message"></div></div>').appendTo(self.screens.errForm);
4194				$('<div class="events2-reg-info"><i class="fa fa-fw fa-phone"></i>Register by phone: call <b>' + self.details.tel + '</b></div>').appendTo(self.screens.errForm);
4195				$('<div class="events2-reg-info"><i class="fa fa-fw am-branches"></i>Register in branch: visit <b>' + self.details.location + '</b></div>').appendTo(self.screens.errForm);
4196				self.eventDetails = $('<div class="events2-reg-details"><div class="events2-reg-thanks-evlocation">' + self.details.location + '</div><div class="events2-reg-thanks-evdate">' + details.datestring + '</div><div class="events2-reg-thanks-evtime">' + details.time_string + '</div></div>');
4197
4198				self.screens.regForm.append(self.eventDetails.clone());
4199				self.screens.paymentScreen.append(self.eventDetails.clone());
4200				self.screens.offlineScreen.append(self.eventDetails.clone());
4201				self.screens.payLaterScreen.append(self.eventDetails.clone());
4202
4203				if (self.details.ezProxyShowLoginButton) {
4204					var loginForm = $('<div style="margin-bottom: 10px; padding-bottom: 10px; border-bottom: 1px solid;"></div>').appendTo(self.screens.regForm);
4205					$('<a href=' + self.details.ezProxyLoginButtonLink + ' class="btn btn-primary">' + self.details.ezProxyLoginButtonText + '</a>').appendTo(loginForm);
4206				} else if (self.eventSettings.events_patron_auth_enabled) {
4207					var loginForm = $('<div class="events2-reg-card-form"></div>').appendTo(self.screens.regForm);
4208					// FD#44334: when login is optional, clarify that the card/PIN fields are
4209					// only used to autofill the signup form, not to gate registration.
4210					if (self.eventSettings.attend_registration_optional_login_info != '') {
4211						$(`<p class="events2-reg-card-help">${self.eventSettings.attend_registration_optional_login_info}</p>`).appendTo(loginForm);
4212					}
4213					if(self.eventSettings.attend_registration_barcode_field_text != '') {
4214						$('<input aria-label="Enter your library card number" class="events2-reg-card" placeholder="' + self.eventSettings.attend_registration_barcode_field_text + '"/>').appendTo(loginForm);
4215					} else {
4216						$('<input aria-label="Enter your library card number" class="events2-reg-card" placeholder="Library card number"/>').appendTo(loginForm);
4217					}
4218					if (!self.eventSettings.client_pinless_auth) {
4219						if (self.eventSettings.attend_registration_pin_field_text != '') {
4220							$('<input aria-label="Enter you PIN number or password" class="events2-reg-pin" type="password" placeholder="' + self.eventSettings.attend_registration_pin_field_text + '"/>').appendTo(loginForm);
4221						} else {
4222							$('<input aria-label="Enter you PIN number or password" class="events2-reg-pin" type="password" placeholder="PIN/password"/>').appendTo(loginForm);
4223						}
4224					}
4225					var btnText = details.login_required ? 'Login' : 'Find details';
4226					$('<button data-loading-text="<i class=\'fa fa-circle-o-notch fa-spin\'></i>" class="btn btn-primary reg-btn">' + btnText + '</button>').appendTo(loginForm);
4227
4228					if (!self.details.login_required && self.eventSettings.client_pinless_auth) {
4229						loginForm.hide();
4230					}
4231				}
4232
4233				var detailsForm = $('<div class="row">' +
4234					'<div class="col-sm-7">' +
4235					'<div class="form-horizontal events2-reg-form">' +
4236					'</div>' +
4237					'</div>' +
4238					'<div class="col-sm-5 guests"></div>' +
4239					'</div>').appendTo(self.screens.regForm);
4240
4241				if (self.eventSettings.events_patron_auth_enabled && self.details.login_required) {
4242					loginForm.show();
4243					detailsForm.hide();
4244					self.regBtn.hide();
4245				}
4246
4247				if (self.details.guests_allowed && +self.disableGuestDetails === 0) {
4248					$('<div>' +
4249						'<b>Register more people?</b>' +
4250						'<span class="events2-add-more btn btn-info pull-right">
4250add more people</span>' +
4251						'</div>' +
4252						'<ul class="events2-more-people-list"></ul>').appendTo($('.guests', self.screens.regForm));
4253				}
4254
4255				self.Questions = $('<div class="amrp-questions"></div>').appendTo($('.events2-reg-form', self.screens.regForm));
4256				$('<p class="amrp-key" style="margin-bottom: 2rem;"><span style="margin-right: 0.5rem; font-size: 18px;">&#9432;</span> Required fields are marked with an asterisk (<span class="required-field"></span>)</p>').prependTo(self.Questions);
4257				self.customQuestions = $('<div class="amrp-questions amrp-custom-questions"></div>').appendTo($('.events2-reg-form', self.screens.regForm));
4258				$('<div class="events2-error-message"></div>').appendTo(self.screens.regForm);
4259
4260				self._createField('first_name', 'text', 'First name', true).appendTo(self.Questions);
4261				self._createField('last_name', 'text', 'Last name', true).appendTo(self.Questions);
4262
4263				if (!self.details.login_required && self.eventSettings.client_pinless_auth) {
4264					self._createField('librarycard', 'text', 'Library card number').appendTo(self.Questions);
4265				} else {
4266					$('<input type="hidden" class="form-control" id="librarycard">').appendTo($('.events2-reg-form', detailsForm));
4267				}
4268
4269				self._createField('email', 'text', 'Email', self.eventSettings.events_require_email, false, 'We\'ll only use this email address to send confirmation and any notifications about the event.').appendTo(self.Questions);
4270				self._createField('phone', 'text', 'Phone', self.eventSettings.events_require_phone, false, 'We\'ll only use the phone number to contact you about the event.').appendTo(self.Questions);
4271
4272				if (self.showSMSPrompt) {
4273					var checked = parseInt(self.SMSOptMode) === 1 ? 'checked="checked"' : '';
4274					var cbx = $('<div class="row amf-row">' +
4275						'<label for="phone" class="col-sm-4 control-label">&nbsp;</label>' +
4276						' <div class="col-sm-8 field">' +
4277						' 	<div class="checkbox"><label style="font-size:12px;"><input style="width:auto !important;" type="checkbox" id="allow_sms"' + checked + '/>' + self.SMSPromptMessage + '</label></div>' +
4278						' </div></div>');
4279					cbx.appendTo(self.Questions);
4280				}
4281
4282				if (self.attendanceType == undefined || self.attendanceType == 'UNKNOWN') {
4283					if (
4284						parseInt(self.details.virtual_registration_enabled) == 1 ||
4285						parseInt(self.details.in_branch_registration_enabled) == 1
4286					) {
4287						self._createField('attendance', 'select', 'Attendance location').appendTo(self.Questions);
4288						if (parseInt(self.details.max_attendee_virtual) > 0) $('#attendance', self.screens.regForm).append('<option value="ONLINE">Online</option>');
4289						if (parseInt(self.details.max_attendee_in_branch) > 0) $('#attendance', self.screens.regForm).append('<option value="INPERSON">In-person at the ' + self.details.location + ' branch</option>');
4290					}
4291				}
4292
4293				if (self.details.librarycardnumber) $('#librarycard', self.screens.regForm).val(self.details.librarycardnumber);
4294				if (self.details.patron && self.details.patron.data && self.details.patron.data.names[0]) $('#first_name', self.screens.regForm).val(self.details.patron.data.names[0].first_name);
4295				if (self.details.patron && self.details.patron.data && self.details.patron.data.names[0]) $('#last_name', self.screens.regForm).val(self.details.patron.data.names[0].last_name);
4296				if (self.details.patron && self.details.patron.data && self.details.patron.data.emails[0]) $('#email', self.screens.regForm).val(self.details.patron.data.emails[0]);
4297				if (self.details.patron && self.details.patron.data && self.details.patron.data.phones[0]) $('#phone', self.screens.regForm).val(self.details.patron.data.phones[0]);
4298
4299				if (self.eventSettings.events_age_enabled) {
4300					var age = self._createField('age', 'select', 'Age', self.eventSettings.events_require_age).appendTo(self.Questions);
4301					$('#age', self.screens.regForm).empty().append('<option value="">Select age group</option>');
4302				}
4303
4304				// Event Tickets Drop Down....
4305				if (typeof self.details.ticketInfo !== 'undefined') {
4306					if (+self.details.enable_multiple_types === 1) {
4307						// Then there is class/ticketdata info
4308						var lastTicketCost = 0.00;
4309						var coEventBillingDD = null;
4310						var coEventBillingList = null;
4311						var enableBilling = parseInt(self.details.enable_billing) === 1;
4312
4313						//var paymentForm =
4314
4315
4316						if (!isNaN(self.disableGuestDetails) && +self.disableGuestDetails === 0) {
4317							coEventBillingDD = new EventBillingDropdown(self.details.recurring_id, 1, self.details.ticketInfo, enableBilling).dropdown;
4318							coEventBillingDD.appendTo(self.Questions);
4319							$('#ticket-dd', self.screens.regForm).on('change', function () {
4320								ticketDropdownEvent(self.screens.regForm);
4321							});
4322						} else {
4323							coEventBillingList = new EventBillingMultipleSelector(self.details.recurring_id, 1, self.details.ticketInfo, enableBilling, parseInt(self.details.seat_limit), 1).selector;
4324							coEventBillingList.appendTo($('.guests', self.screens.regForm));
4325
4326							$('.list-ticket-qty-dd', self.screens.regForm).off().on('change', function () {
4327								var calculated = calculateTickets();
4328								if (!calculated) {
4329									alert('Cannot add selected quantity of registration types, it will exceed seat limit per registration');
4330								}
4331							});
4332						}
4333					} else {
4334						if (+self.details.enable_billing === 1) {
4335							var cost = parseFloat(self.details.ticketInfo.amount).toFixed(2);
4336							ticket = {
4337								type: self.details.ticketInfo.typeId,
4338								cost: cost,
4339								name: 'Fixed Registration Cost - ' + self.eventSettings.payment_currency_symbol + '' + cost,
4340								id: 'main'
4341							};
4342
4343							var found = -1;
4344							if (self.tickets.length > 0) {
4345								for (var t = 0; t < self.tickets.length; t++) {
4346									var tkt = self.tickets[t];
4347									if (typeof tkt.id !== 'undefined') {
4348										if (tkt.id === 'main') {
4349											self.tickets[t] = ticket;
4350											refreshTicketList();
4351											return;
4352										}
4353									}
4354								}
4355							}
4356
4357							self.tickets.push(ticket);
4358							refreshTicketList();
4359						}
4360					}
4361					var offlineFormText = 'Thank you for registering.';
4362					if (+self.enableBilling === 1) {
4363						offlineFormText = self.eventSettings.events_offline_payments_message;
4364					}
4365
4366					self.showPayment = self.eventSettings.events_ecommerce_enabled && parseInt(self.details.enable_billing, 10) === 1;
4367					self.showOffline = self.eventSettings.events_patron_offline_payments_enabled;
4368
4369
4370					//var coEventBillingForm = new EventBillingPaymentForm({ off: false, txt: ''}, self.showOffline).form;
4371					self.PayPalPayFlow = new PayPalPayFlow('', self.ppTestMode, $("meta[name='client']").attr('content'));
4372					var coEventBillingOfflineForm = new EventBillingPaymentForm({ off: true, txt: offlineFormText }, self.showOffline).form;
4373					coEventBillingOfflineForm.appendTo(self.screens.offlineScreen);
4374					var coEventBillingPayLaterForm = new EventBillingPaymentForm({ off: true, txt: self.eventSettings.rooms_later_payments_message }, self.showOffline).form;
4375					coEventBillingPayLaterForm.appendTo(self.screens.payLaterScreen);
4376				}
4377
4378				if (self.details.registration_fields && self.details.registration_fields.fields) {
4379					$.each(self.details.registration_fields.fields, function (index, val) {
4380						var field = self._createFieldWithObject(val).data('fieldSettings', val).addClass('amrp-custom-field').appendTo(self.customQuestions);
4381						if (val.type === 'select') {
4382							var select = $('select', field);
4383							$('<option value="">Please choose...</option>').appendTo(select);
4384							var options = val.options.trim().split(/\r?\n/);
4385							for (var i = 0; i < options.length; i++) {
4386								$('<option>' + options[i] + '</option>').appendTo(select);
4387							}
4388						}
4389					});
4390				}
4391
4392				if (self.patron && self.patron.data) {
4393					if (!self.eventSettings.client_pinless_auth) {
4394						if (self.patron.data.names.length > 0) {
4395							self.screens.regForm.find('#first_name').val(self.patron.data.names[0].first_name);
4396							self.screens.regForm.find('#last_name').val(self.patron.data.names[0].last_name);
4397						}
4398						if (self.patron.data.phones.length > 0) {
4399							self.screens.regForm.find('#phone').val(self.patron.data.phones[0]);
4400						}
4401						if (self.patron.data.emails.length > 0) {
4402							self.screens.regForm.find('#email').val(self.patron.data.emails[0]);
4403						}
4404					}
4405
4406					if (self.patron.data.barcodes.length > 0) {
4407						self.screens.regForm.find('#librarycard').val(self.patron.data.barcodes[0]);
4408					}
4409
4410					loginForm.hide();
4411					detailsForm.show();
4412					self.regBtn.show();
4413				}
4414
4415				if (self.eventSettings.events_age_enabled) {
4416					$.getJSON(self.apiServer + '/v1/' + self.keyword + '/eventsages', { type: 'singular' }, function (json, textStatus) {
4417						$select = $('#age', self.screens.regForm).empty().append('<option value="">Select age group</option>');
4418						$.each(json, function (index, val) {
4419							$('<option>' + val.name + '</option>').appendTo($select);
4420						});
4421					});
4422				}
4423
4424				var paymentTypes = [
4425					{
4426						string: 'card',
4427						cond: self.eventSettings.events_ecommerce_enabled && parseInt(self.details.enable_billing, 10) === 1 && self.eventSettings.events_card_enabled,
4428						buttonText: 'Card',
4429						screen: 'paymentScreen'
4430					},
4431					{
4432						string: 'pay_later',
4433						cond: self.eventSettings.events_ecommerce_enabled && self.eventSettings.events_patron_pay_later_enabled,
4434						buttonText: self.eventSettings.rooms_pay_later_button_text || 'Pay Later',
4435						screen: 'payLaterScreen'
4436					},
4437					{
4438						string: 'offline',
4439						cond: self.eventSettings.events_patron_offline_payments_enabled,
4440						buttonText: self.eventSettings.rooms_offline_button_text || 'Offline',
4441						screen: 'offlineScreen'
4442					}
4443				];
4444
4445				self.paymentOptions = $('<div class="events2-additional-dates"></div>');
4446
4447				// Determine which payment types are enabled and only show those buttons
4448				var buttonHtml = '';
4449				paymentTypes.forEach(function (paymentType) {
4450					if (paymentType['cond']) {
4451						self.availablePaymentTypes.push(paymentType['string']);
4452						var isActiveString = '';
4453						var isCheckedString = '';
4454						// Pre-select button for default payment type
4455						if (self.bookingPaymentType === paymentType['string']) {
4456							isActiveString = 'active';
4457							isCheckedString = 'checked';
4458						}
4459
4460						buttonHtml +=
4461							'<label class="btn btn-default ' + isActiveString + '">'
4462								+ '<input type="radio" name="options" value="' + paymentType['string'] + '" autocomplete="off" ' + isCheckedString + '>'
4463								+ paymentType['buttonText'] +
4464							'</label>';
4465					}
4466				})
4467
4468				$('<div class="row amf-row amnp-payment-toggle">'
4469				+ '<div class="row amf-row">'
4470				+ '<div class="col-sm-4">'
4471				+ '<label class="control-label">Payment type</label>'
4472				+ '</div>'
4473				+ '<div class="col-sm-7 field">'
4474				+ '<div class="btn-group" data-toggle="buttons" style="display:flex">'
4475				+ buttonHtml
4476				+ '</div>'
4477				+ '</div>'
4478				+ '</div>'
4479				+ '</div>'
4480				+ '</div>').appendTo(self.paymentOptions);
4481
4482				$('input[name="options"]', self.paymentOptions).on('change', function () {
4483					if ($(this).val() === 'card') {
4484						self.isOffline = false;
4485						self.showOffline = false;
4486					} else if ($(this).val() === 'pay_later') {
4487						self.isOffline = true;
4488						self.showOffline = true;
4489					} else {
4490						self.isOffline = true;
4491						self.showOffline = true;
4492					}
4493				});
4494
4495				self.paymentOptions.on('change', ':input', function () {
4496					self.bookingPaymentType = $(this).val();
4497				});
4498
4499				if (self.availablePaymentTypes.length > 1 && parseInt(self.details.enable_billing)) {
4500					(self.paymentOptions).appendTo(self.screens.regForm);
4501				}
4502
4503				// Get event series information
4504				$.getJSON(self.apiServer + '/v1/' + self.keyword + '/eventsseries/' + self.recurringid, function (json, textStatus) {
4505					self.extraDates = [];
4506					self.extraDatesFutureOpenReg = [];
4507					$.each(json, function (index, val) {
4508						val.changed = parseInt(val.changed, 10);
4509						if (val.changed === 1) {
4510							return;
4511						}
4512						if (moment(val.close_registration).diff(moment()) > 0 && (moment(val.open_registration).diff(moment()) < 0 || val.open_registration == "0000-00-00 00:00:00") && val.id != self.eventid) {
4513							var seatsAvailable = {
4514								'INPERSON': function(){ return (self.details.max_attendee_in_branch - val.total_registrants); },
4515								'ONLINE': function(){ return (self.details.max_attendee_virtual - val.total_registrants); },
4516								'HYBRID': function() { return (self.details.max_attendee - val.total_registrants); },
4517								'': function() { return (self.details.max_attendee - val.total_registrants); }
4518							};
4519							self.extraDates.push({
4520								id: val.id,
4521								total_registrants: val.total_registrants,
4522								datestring: (val.changed === 2) ? val.changed_datestring : val.datestring,
4523								time_string: (val.changed === 2) ? val.changed_time_string : val.time_string,
4524								seats_available: seatsAvailable['' + val.event_type]()
4525							});
4526						}
4527						if (moment(val.open_registration).diff(moment()) > 0) {
4528							self.extraDatesFutureOpenReg.push({
4529								datestring: (val.changed === 2) ? val.changed_datestring : val.datestring,
4530								time_string: (val.changed === 2) ? val.changed_time_string : val.time_string,
4531								reg_opens: val.open_registration
4532							})
4533						}
4534					});
4535
4536
4537					if (self.extraDates.length > 0) {
4538						self.additionalDates = $('<div class="events2-additional-dates"></div>').appendTo(self.screens.regForm);
4539						var announce = "You will also be registered for these additional dates";
4540						if (self.regtype == 2) {
4541							announce = "You will also be wait-listed for these additional dates";
4542						}
4543
4544						if (parseInt(self.details.force_series_registration, 10) == 1) {
4545							$('<h4>' + announce + '</h4>').appendTo(self.additionalDates);
4546						} else {
4547							$('<h4>Also register for these additional dates</h4>').appendTo(self.additionalDates);
4548							$('<span class="events2-additional-dates-all">(<a href="#">check all</a>)</span>').appendTo(self.additionalDates);
4549						}
4550
4551						// Modify list to show context, or rather, intent
4552						// CH8320 - Added space to 'seats remaining and join waitlist to prevent seat number from overlapping.
4553						$.each(self.extraDates, function (index, val) {
4554							$('<label class="c-input c-checkbox" data-seatsavailable="' + val.seats_available + '">' +
4555								'<input type="checkbox" value="' + val.id + '" data-waitlist="' + (val.seats_available <= 0) + '">' +
4556								'<span class="c-indicator"></span>' +
4557								' ' + val.datestring + ': ' + val.time_string + ' <i>( ' + (val.seats_available > 0 ? val.seats_available + ' Seats remaining' : ' Join Waitlist') + ' )</i>' +
4558								'</label>').appendTo(self.additionalDates);
4559						});
4560
4561						/*$.each(self.extraDatesFutureOpenReg, function (index, val) {
4562							$('<label>' +
4563								'<span class="c-indicator"></span>' +
4564								' ' + val.datestring + ': ' + val.time_string + ' <i>(Registration opens: ' + val.reg_opens + ')</i>' +
4565								'</label>').appendTo(self.additionalDates);
4566						});*/
4567
4568						$('.c-checkbox', self.additionalDates).off().on('click', function () {
4569							var input = $(this).children('input').first();
4570							var checked = input.is(":checked");
4571							var v = input.val();
4572							if (checked) {
4573								if (self.selectedDates.length > 0) {
4574									for (var s = 0; s < self.selectedDates.length; s++) {
4575										if (self.selectedDates[s].id === v) {
4576											self.selectedDates[s].intent = input.attr("data-waitlist") === "true" ? 2 : 1;
4577											return;
4578										}
4579									}
4580								}
4581								// If we are out here we didn't find an existing one
4582								self.selectedDates.push({ id: v, intent: (input.attr("data-waitlist") === "true") ? 2 : 1 });
4583							} else {
4584								if (self.selectedDates.length > 0) {
4585									var index = -1;
4586									for (var s = 0; s < self.selectedDates.length; s++) {
4587										if (self.selectedDates[s].id === v) {
4588											index = s;
4589										}
4590									}
4591
4592									if (index > -1) {
4593										self.selectedDates.splice(index, 1);
4594									}
4595								}
4596							}
4597
4598							if (self.enableMultipleTypes || self.enableBilling) {
4599								refreshTicketList();
4600							}
4601						});
4602
4603						$('input', self.additionalDates).prop({ 'checked': force, 'disabled': force });
4604						if (force) {
4605							self.selectedDates = [];
4606							$('input', self.additionalDates).each(function () {
4607								self.selectedDates.push({ id: $(this).val(), intent: ($(this).attr("data-waitlist") === "true") ? 2 : 1 });
4608							});
4609							refreshTicketList();
4610						}
4611
4612						// Set date checkboxes to disabled ONLY if waitlist not allowed.
4613						$("input", self.additionalDates).filter(function () {
4614							return parseInt($(this).closest('label').attr("data-seatsavailable"), 10) <= 0;
4615						}).prop({ 'checked': (force || whole), 'disabled': (force || whole) });
4616					}
4617				});
4618
4619				self.screens.regForm.on('click', '.events2-add-more', function (event) {
4620					event.preventDefault();
4621					var form = $(this).closest('.events2-reg-popup').find('.events2-reg-form');
4622					var attendanceType = ((self.attendanceType == undefined || self.attendanceType == 'UNKNOWN') ? $('#attendance', form).val() : self.attendanceType);
4623
4624					self.mayOptForWaitlist = false;
4625					if (self.regtype == 1 &&
4626						((((attendanceType !== 'ONLINE' && parseInt(self.details.in_branch_registration_enabled) == 1)) && (parseInt(self.details.max_attendee_in_branch, 10) - parseInt(self.details.total_inperson_registrants, 10) - self.guests.length) <= 1)) ||
4627						((((attendanceType === 'ONLINE' && parseInt(self.details.virtual_registration_enabled) == 1)) && (parseInt(self.details.max_attendee_virtual, 10) - parseInt(self.details.total_online_registrants, 10) - self.guests.length) <= 1))
4628					) {
4629						var n = attendanceType === 'ONLINE' ?
4630							(parseInt(self.details.max_attendee_virtual, 10) - parseInt(self.details.total_registrants, 10)) :
4631							(parseInt(self.details.max_attendee_in_branch, 10) - parseInt(self.details.total_registrants, 10));
4632						var canWaitlist = allowWaitlist && !waitlistClosed;
4633						var remainingSeatsMessage = "";
4634						switch (n) {
4635							case 0:
4636								remainingSeatsMessage = "There are no seats left for this event.";
4637								break;
4638							case 1:
4639								remainingSeatsMessage = "There is only 1 seat left for this event.";
4640								break;
4641							default:
4642								remainingSeatsMessage = "There are " + n + " seats left for this event.";
4643								break;
4644						}
4645						if (!canWaitlist) {
4646							alert(remainingSeatsMessage + " You cannot add any more registrants.");
4647							return;
4648						} else {
4649							self.mayOptForWaitlist = true;
4650							alert(remainingSeatsMessage + " You will be waitlisted if you add more registrants.");
4651						}
4652					}
4653
4654					if (parseInt(self.details.seat_limit, 10) > 0) {
4655						if (self.guests.length + 1 > parseInt(self.details.seat_limit, 10)) {
4656							alert('Sorry you cannot book more than ' + self.details.seat_limit + ' seats at once.');
4657							return;
4658						}
4659					}
4660
4661					var list = $('.events2-more-people-list', self.screens.regForm);
4662					self.personPopup = $('<div class="events2-reg-person-popup"></div>').amPopup({ title: 'Add person', popUpClass: 'events2-person-popup' });
4663
4664					var stage = $('<div class="events2-reg-person-stage"></div>').appendTo(self.personPopup);
4665					var footer = $('<div class="events2-reg-person-footer"><div class="events2-error-message"></div></div>').appendTo(self.personPopup);
4666					var person = $('<div class="form-horizontal amrp-questions"></div>').appendTo(stage);
4667					$('<p class="amrp-key" style="margin-bottom: 2rem;"><span style="margin-right: 0.5rem; font-size: 18px;">&#9432;</span> Required fields are marked with an asterisk (<span class="required-field"></span>)</p>').prependTo(person);
4668
4669					self._createField('first_name', 'text', 'First name', true).appendTo(person);
4670					self._createField('last_name', 'text', 'Last name', false).appendTo(person);
4671
4672					if (parseInt(self.details.enable_multiple_types) === 1) {
4673						var enableBilling = parseInt(self.details.enable_billing) === 1;
4674						var updateCount = (self.tickets.findIndex(function (t) { return t.id === 'main'; })) === 0;
4675						if (!self.mainTicketAdjusted && updateCount) self.mainTicketAdjusted = true;
4676						drawEventBillingDropDown(self.details.ticketInfo, self.tickets, enableBilling, self.details.recurring_id, person, 1, updateCount, self.mainTicketAdjusted);
4677					}
4678
4679					if (self.eventSettings.events_age_enabled) {
4680						var age = self._createField('age', 'select', 'Age', self.eventSettings.events_require_age).appendTo(person);
4681
4682
4683						$.getJSON(self.apiServer + '/v1/' + self.keyword + '/eventsages', { type: 'singular' }, function (json, textStatus) {
4684							$select = $('#age', stage).empty().append('<option value="">Select age group</option>');
4685							$.each(json, function (index, val) {
4686								$('<option>' + val.name + '</option>').appendTo($select);
4687							});
4688						});
4689					}
4690
4691					$('<button class="btn btn-info">add</button>').on('click', function (event) {
4692						event.preventDefault();
4693
4694						if (self.mayOptForWaitlist) {
4695							self.excessGuests += 1;
4696						}
4697						updateButtonText(true);
4698
4699						if (parseInt(seat_limit, 10) == 0 || (parseInt(seat_limit, 10) >= 0 && self.guests.length < (parseInt(seat_limit, 10) - 1))) {
4700							var age = null;
4701							if (self.eventSettings.events_age_enabled) {
4702								age = $('#age', person).val();
4703							}
4704
4705							var first_name = $('#first_name', person).val().trim();
4706							var last_name = $('#last_name', person).val().trim();
4707							var ticketName = '';
4708							var ticketType = 0;
4709							var ticketCost = 0.00;
4710							var ticketCostId = 0;
4711							var ticketSet = false;
4712
4713							if (typeof self.details.ticketInfo !== 'undefined') {
4714								if (+self.details.enable_multiple_types === 1) {
4715									ticketType = parseInt($('#ticket-dd', person).val());
4716									ticketName = $('#ticket-dd :selected', person).text();
4717									ticketCost = parseFloat($('#ticket-dd > option:selected', person).attr('data-cost'));
4718									ticketSet = true;
4719								} else {
4720									if (+self.details.enable_billing === 1) {
4721										ticketType = -1;
4722										ticketName = 'Guest - Fixed Registration Cost - ' + self.eventSettings.payment_currency_symbol + '' + parseFloat(self.details.ticketInfo.amount).toFixed(2);
4723										ticketCost = parseFloat(self.details.ticketInfo.amount).toFixed(2);
4724										ticketSet = true;
4725									}
4726								}
4727							}
4728
4729							if (!ticketSet && +self.details.enable_multiple_types === 1) {
4730								alert('Select a registration type before adding guests.');
4731								return;
4732							}
4733
4734							if (self._isFormClean(person)) {
4735								var guestData = { first_name: first_name, last_name: last_name, age: age, id: 'g' + self.guests.length };
4736								// -1 = Single cost, 0 > = multiple reg types
4737								if (ticketType > 0 || ticketType === -1) {
4738									guestData.ticketType = ticketType;
4739									guestData.ticketName = ticketName;
4740									guestData.ticketCost = ticketCost;
4741									var guestTicket = {
4742										cost: ticketCost, type: ticketType, name: ticketName, id: 'g' + self.guests.length
4743									};
4744									self.tickets.push(guestTicket);
4745								}
4746
4747								self.guests.push(guestData);
4748
4749								$("input", self.additionalDates).filter(function () {
4750									return parseInt($(this).closest('label').attr("data-seatsavailable"), 10) - self.guests.length <= 0;
4751								}).prop({ 'checked': (force || whole), 'disabled': (force || whole) });
4752
4753								self.personPopup.data('plugin_amPopup').close();
4754								drawEventBillingDropDown(self.details.ticketInfo, [guestTicket], enableBilling, self.details.recurring_id, self.screens.regForm, 0, 1, 0);
4755								refreshTicketList();
4756								renderList();
4757							}
4758						} else if (parseInt(seat_limit, 10) > 0) {
4759							// This is the "add" button for new registrants
4760							var guestSeats = parseInt(seat_limit);
4761							alert('Sorry, we were unable to add this guest. There is a limit of ' + guestSeats + ' guests per registration for this event.');
4762						}
4763					}).appendTo(footer);
4764
4765					self.personPopup.data('plugin_amPopup').open();
4766				}).on('click', '.events2-more-people-list .btn', function (event) {
4767					event.preventDefault();
4768
4769					self.excessGuests -= 1;
4770					updateButtonText(true);
4771
4772					var gi = $(this).closest('li').index();
4773					self.guests.splice(gi, 1);
4774
4775					for (var t = 0; t < self.tickets.length; t++) {
4776						if (self.tickets[t].id === 'g' + gi) {
4777							var removed = self.tickets.splice(t, 1);
4778							// We need to update the available counts in ticketInfo
4779							updateTicketData(removed, self.details.ticketInfo, self.enableBilling, self.details.recurring_id, self.screens.regForm, 1, 'add');
4780							refreshTicketList();
4781							break;
4782						}
4783					}
4784
4785					renderList();
4786				}).on('click', '.events2-additional-dates-all a', function (event) {
4787					event.preventDefault();
4788					self.selectedDates = [];
4789					$(this).closest('.events2-additional-dates').find('input[type=checkbox]:enabled').each(function () {
4790						self.selectedDates.push({ id: $(this).val(), intent: ($(this).attr("data-waitlist") === "true") ? 2 : 1 });
4791						$(this).prop('checked', true);
4792					});
4793
4794					if (self.enableMultipleTypes || self.enableBilling) {
4795						refreshTicketList();
4796					}
4797
4798					return false;
4799				}).on('click', '.events2-reg-card-form button', function (event) {
4800					event.preventDefault();
4801					self.regBtn.button('loading');
4802					var p = $(this).closest('.events2-reg-popup');
4803
4804					// CH#1942 - Trim the card/pin fields to prevent blanks.
4805					var card = $.trim(p.find('.events2-reg-card').val());
4806					if (card.length == 0) {
4807						p.find('.events2-error-message').text('Card number is required').fadeIn().delay(3000).fadeOut();
4808						//self.regBtn.button('reset');
4809						return;
4810					}
4811
4812					if (!self.eventSettings.client_pinless_auth) {
4813						var pin = $.trim(p.find('.events2-reg-pin').val());
4814						if (pin.length == 0) {
4815							p.find('.events2-error-message').text('Pin is required').fadeIn().delay(3000).fadeOut();
4816							//self.regBtn.button('reset');
4817							return;
4818						}
4819					}
4820
4821					var loginData = { u: card, p: pin, 'type': 'attend', eventid: self.eventid }
4822					if (!self.eventSettings.client_pinless_auth) {
4823						loginData.p = pin;
4824					}
4825
4826					if (age_restriction) {
4827						loginData['age'] = { min: age_min, max: age_max };
4828					}
4829
4830					loginData['event_login_required'] = self.details.login_required;
4831
4832					$.getJSON(self.apiServer + '/v1/' + self.keyword + '/patron', loginData, function (json, textStatus) {
4833						if (json.result == 'ok') {
4834							if (self.eventSettings.events_patron_auth_enabled && self.details.login_required) {
4835								loginForm.hide();
4836								detailsForm.show();
4837							}
4838
4839							if (!self.eventSettings.client_pinless_auth) {
4840								if (json.data.names.length > 0) {
4841									p.find('#first_name').val(json.data.names[0].first_name);
4842									p.find('#last_name').val(json.data.names[0].last_name);
4843									if (self.eventSettings.events_patron_details_readonly) {
4844										p.find('#first_name').prop('disabled', true);
4845										p.find('#last_name').prop('disabled', true);
4846									}
4847								}
4848								if (json.data.phones.length > 0) {
4849									p.find('#phone').val(json.data.phones[0]);
4850									if (self.eventSettings.events_patron_details_readonly) {
4851										p.find('#phone').prop('disabled', true);
4852									}
4853								}
4854								if (json.data.emails.length > 0) {
4855									p.find('#email').val(json.data.emails[0]);
4856									if (self.eventSettings.events_patron_details_readonly) {
4857										p.find('#email').prop('disabled', true);
4858									}
4859								}
4860							}
4861							if (json.data.barcodes.length > 0) {
4862								p.find('#librarycard').val(json.data.barcodes[0]);
4863							}
4864							p.find('.events2-reg-card').val('');
4865							p.find('.events2-reg-pin').val('');
4866						} else {
4867							var msg = self.eventSettings.client_pinless_auth ? 'Sorry, card number not found' : 'Sorry, pin or card number not found';
4868							if (json.message && json.message.length > 0) {
4869								msg = json.message;
4870							}
4871							p.find('.events2-error-message').text(json.message || msg).fadeIn().delay(3000).fadeOut();
4872						}
4873
4874						self.regBtn.button('reset');
4875					}).error(function () {
4876						p.find('.events2-error-message').text('Sorry, there was a problem making the request').fadeIn().delay(3000).fadeOut();
4877						self.regBtn.button('reset');
4878					});
4879
4880				});
4881
4882				self.screens.errForm.hide();
4883				self.screens.regForm.show();
4884
4885				self.popup.on('focus', '.amrp-missing-field', function (event) {
4886					$(this).removeClass('amrp-missing-field');
4887				});
4888				self.popup.data('plugin_amPopup').open();
4889
4890				if (self.regtype == 2) {
4891					if (!allowWaitlist) {
4892						self.regBtn.removeClass('btn-default').addClass('btn-primary');
4893						updateButtonText('Registration not available', true);
4894					} else {
4895						self.regBtn.removeClass('btn-default').addClass('btn-primary');
4896						updateButtonText('Join the wait list', true);
4897					}
4898				} else {
4899					self.regBtn.removeClass('btn-default').addClass('btn-primary');
4900					updateButtonLoading(false);
4901				}
4902
4903				self.popup.on('focus', '.amrp-missing-field', function (event) {
4904					$(this).removeClass('amrp-missing-field');
4905				});
4906
4907				if (+self.showPayment === 1) {
4908					self.PayPalPayFlow.buildForm(self.keyword).then(function (form) {
4909						form.appendTo(self.screens.paymentScreen);
4910						self.popup.data('plugin_amPopup').open();
4911					});
4912				} else {
4913					self.popup.data('plugin_amPopup').open();
4914				}
4915			});
4916		}
4917	});
4918	return this;
4919};
4920/*************************************end regButton*******************************************/
4921
4922/************************************start  amRecReads****************************************/
4923$.fn.amRecReads = function (options) {
4924	this.each(function (index, el) {
4925		var self = $(this);
4926		if (!self.data('amRecReads')) {
4927			self.data('amRecReads', true);
4928			self.options = $.extend({}, $.fn.amRecReads.defaults, options);
4929			self.hide();
4930			self.holder = $('<div class="recreads-holder"></div>').insertAfter(self);
4931			self.stage = $('<div class="recreads-stage"></div>').appendTo(self.holder);
4932			self.sections = $('<div class="recreads-sections"></div>').appendTo(self.holder);
4933			self.currentSection = $('<div class="recreads-current-section"></div>').appendTo(self.holder);
4934
4935			$('<div class="recreads-section-title vtab"></div>').append('<span>Categories</span>').on('mouseenter', function (event) {
4936				event.preventDefault();
4937				openSections();
4938			}).appendTo(self.sections);
4939			var i = 1;
4940			$('>li', self).each(function (id, sectionInfo) {
4941				var list = $('>ul', this);
4942				$('<div class="recreads-section-title vtab"></div>')
4943					.append('<span>' + $(sectionInfo).text().trim() + '</span>')
4944					.addClass('bg-colour' + i)
4945					.on('click', function (event) {
4946						event.preventDefault();
4947						var v = $(this).clone()
4948						v.addClass('vtab_selected');
4949
4950						self.currentSection.empty().append(v);
4951						self.stage.empty().append(list.clone());
4952						closeSections();
4953					})
4954					.appendTo(self.sections);
4955				i++;
4956			});
4957			$('.recreads-section-title', $(self).parent()).first().next().trigger('click');
4958		}
4959		self.sections.on('mouseleave', function (event) {
4960			event.preventDefault();
4961			closeSections();
4962		});
4963		function closeSections() {
4964			self.sections.animate({
4965				left: '100%',
4966			}).removeClass('recreads-sections-open');
4967
4968		}
4969		function openSections() {
4970			self.sections.animate({
4971				left: self.holder.outerWidth(true) - self.sections.outerWidth(),
4972			}).addClass('recreads-sections-open');
4973		}
4974	});
4975	return this;
4976};
4977/*************************************end amRecReads*******************************************/
4978
4979/************************************start  amBookList****************************************/
4980$.fn.amBookList = function (options) {
4981	this.each(function (index, el) {
4982		var self = $(this);
4983		self.defaults = {
4984			title: 'Our Recommended Reads'
4985		};
4986		if (!self.data('amBookList')) {
4987			self.data('amBookList', true);
4988			self.options = $.extend({}, self.defaults, options);
4989			self.hide();
4990			self.show = false;
4991			self.recordSets = [];
4992			var title = self.attr('data-title') || self.options.title;
4993			self.holder = $('<div class="ambl-holder"></div>').insertAfter(self);
4994			self.holder.append('<img tabindex="0" class="ambl-events-slideshow-button ' + self.attr('id') + ' ambl-events-slideshow-left" alt="Previous slide" title="Previous slide" aria-label="Previous slide" caption="false" src="/images/next-left.png">');
4995			self.holder.append('<img tabindex="0" class="ambl-events-slideshow-button ' + self.attr('id') + ' ambl-events-slideshow-right" alt="Next slide" title="Next slide" aria-label="Next slide" caption="false" src="/images/next-right.png"></div>');
4996			self.catList = $('<div class="ambl-catlist"><div class="ambl-cat-title">' + title + '</div></div>').appendTo(self.holder);
4997			self.linkBase = self.attr('data-polaris-server') + '/view.aspx?cn=';
4998			self.vegaUrl = self.attr('data-vega-server') || false;
4999			self.orgID = parseInt(self.attr('data-org-id')) > 0 ? parseInt(self.attr('data-org-id')) : 1;
5000			self.perPage = self.attr('data-count');
5001			init();
5002
5003			function init() {
5004				self.catList.on('click', '>span', function (event) {
5005					event.preventDefault();
5006					event.stopPropagation();
5007					self.holder.removeClass('open');
5008					showSet($(this).data('list'));
5009				}).on('mouseenter', function (event) {
5010					event.preventDefault();
5011					self.holder.addClass('open');
5012				}).on('mouseleave', function (event) {
5013					event.preventDefault();
5014					self.holder.removeClass('open');
5015				}).on('click', function (event) {
5016					event.preventDefault();
5017					self.holder.toggleClass('open');
5018				});
5019
5020				$('>li', self).each(function (id, recordSet) {
5021					self.recordSets.push({ id: $(recordSet).find('>a').attr('data-set-id'), title: $(recordSet).find('>a').text() });
5022				});
5023				$.each(self.recordSets, function (index, val) {
5024					$('<span></span>').text(val.title).data('list', val).appendTo(self.catList);
5025				});
5026
5027				if (self.recordSets.length < 2) {
5028					self.catList.hide();
5029				}
5030				showSet(self.recordSets[0]);
5031			}
5032
5033			function showSet(recordSet) {
5034				var w = 75 / self.perPage;
5035				var client = $('meta[name=client]').attr('content');
5036				var apiserver = $('meta[name=apiserver]').attr('content') || 'https://api.communico.co';
5037				$.getJSON(apiserver + '/v1/' + client + '/polaris/search/', { q: 'brs=' + recordSet.id, page: 1, bibsperpage: 120, keyword: '', sortby: 'AU', limit: '' }, function (json, textStatus) {
5038					if (json.result !== 'ok' || json.data.TotalRecordsFound <= 0) return;//TODO: fail better
5039					if (self.show) self.show.cycle('destroy').remove();
5040					self.show = $('<div class="ambl-show" data-cycle-fx="scrollHorz" data-cycle-log="false" data-cycle-next=".' + self.attr('id') + '.ambl-events-slideshow-right" data-cycle-pause-on-hover="true" data-cycle-prev=".' + self.attr('id') + '.ambl-events-slideshow-left" data-cycle-slides=">div" data-cycle-timeout="15000"></div>').appendTo(self.holder);
5041					var c = 0;
5042					var $section = $('<div></div>');
5043					$.each(json.data.BibSearchRows, function (index, val) {
5044						if (c >= self.perPage) {
5045							c = 0;
5046							$section.appendTo(self.show);
5047							$section = $('<div></div>');
5048						}
5049						c++;
5050
5051						var server = index % 10;
5052						var coverUrl = 'https://covers' + server + '.communico.co/' + client + '/cover/?';
5053
5054						if (val.ISBN) {
5055							coverUrl += 'type=isbn&id=' + val.ISBN + '&';
5056						} else if (val.UPC) {
5057							coverUrl += 'type=upc&id=' + val.UPC + '&';
5058						} else if (val.OCLC) {
5059							coverUrl += 'type=oclc&id=' + val.OCLC + '&';
5060						}
5061
5062						coverUrl += 'title=' + encodeURIComponent(val.Title || "No Cover Image Available");
5063
5064						//create link
5065						var url = self.linkBase + val.ControlNumber + '&orgID=' + self.orgID;
5066						if (self.vegaUrl && self.vegaUrl.length > 0) {
5067							url = self.vegaUrl.replace('{{bibid}}', val.ControlNumber);
5068						}
5069						var $el = $('<a href="' + url + '">'
5070							+ '<img alt="' + val.Title + '" title="' + val.Title + '" caption="false" style="width:' + w + '%" src="' + coverUrl + '">');
5071						$el.appendTo($section);
5072					});
5073					$section.appendTo(self.show);
5074					self.show.cycle();
5075				});
5076			}
5077		}
5078	});
5079	return this;
5080};
5081/*************************************end amBookList*******************************************/
5082
5083/************************************start  amCirculation****************************************/
5084
5085$.fn.amCirculation = function (options) {
5086	this.each(function (index, el) {
5087		var self = $(this);
5088		if (!self.data('amCirculation')) {
5089			self.data('amCirculation', true);
5090			self.options = $.extend({}, $.fn.amCirculation.defaults, options);
5091
5092			// $('.circulation_details', self).qtip({
5093			// 		content: {
5094			// 			attr: 'data-desc'
5095			// 		},
5096			// 		position: {
5097			// 			my: 'left top',
5098			// 			at: 'right bottom',
5099			// 			viewport: $(window)
5100			// 		}
5101			// 	});
5102			self.footer = $('<div class="circulation_footer">| </div>').insertAfter(self);
5103			self.children().hide().first().show();
5104			self.children().each(function (index, el) {
5105				var c = $(this);
5106				$('<span class="link">' + $(this).data('category') + '</span>').appendTo(self.footer).on('click', function () {
5107					$(this).closest('.circulation_footer').find('.active').removeClass('active');
5108					$(this).addClass('active');
5109					self.children().hide();
5110					c.fadeIn();
5111				});
5112				self.footer.append(' |');
5113			});
5114			self.footer.children().first().addClass('active');
5115
5116			$('.circulation_details', self).on('click', function (event) {
5117				event.preventDefault();
5118				var $data = $('<div class="circulation_popup"/>');
5119
5120				var author = $(this).closest('.circulation_info').data('author');
5121				var title = $(this).closest('.circulation_info').data('title');
5122				$data.append('<h3>' + title + '</h3>');
5123				$data.append('<h4>By ' + author + '</h4>');
5124				$(this).closest('.circulation_book').find('.circulation_poster img').clone().appendTo($data);
5125				$data.append($(this).data('desc'));
5126				var $popupwidget = showPopupWidget(title, $data);
5127				$popupwidget.css('width', '460px');
5128				$popupwidget.position({
5129					of: $(window)
5130				});
5131			});
5132
5133			$('.circulation_reserve', self).on('click', function (event) {
5134				event.preventDefault();
5135				var title = $(this).closest('.circulation_info').data('title');
5136				var $data = getLoginForm();
5137				$data.prepend('<p>Reserved your items are held for 7 days, you can collect anytime within this period.</p>');
5138				var $popupwidget = showPopupWidget('Reserve ' + title, $data);
5139				$popupwidget.css('width', '460px');
5140				$popupwidget.position({
5141					of: $(window)
5142				});
5143			});
5144			$('.circulation_pickup', self).on('click', function (event) {
5145				event.preventDefault();
5146				var title = $(this).closest('.circulation_info').data('title');
5147				var $data = getLoginForm();
5148				$data.prepend('<p>You can collect your item on your way out of the branch (please allow 15 minutes after your request)</p>');
5149
5150				var $popupwidget = showPopupWidget('Pickup ' + title, $data);
5151				$popupwidget.css('width', '460px');
5152				$popupwidget.position({
5153					of: $(window)
5154				});
5155			});
5156
5157			function getLoginForm() {
5158				var $form = $('<div/>');
5159				$('<p><b>
5159Log in with either your Library Card Number or EZ Login</b></p>').appendTo($form);
5160				$('<div class="form-group"><label for="libid">Library ID or EZ Username</label><input type="text" class="form-control input-sm" name="libid" id="libid"></div>').appendTo($form);
5161				$('<div class="form-group"><label for="password">Phone (Last four digits) or EZ Password</label><input type="password" class="form-control input-sm" name="password" id="password"></div>').appendTo($form);
5162				$('<button class="button">Log in</button>').appendTo($form);
5163				return $form;
5164			}
5165		}
5166	});
5167	return this;
5168};
5169/*************************************end amCirculation*******************************************/
5170
5171/************************************start  amSierraRecReads****************************************/
5172$.fn.amSierraRecReads = function (options) {
5173	this.each(function (index, el) {
5174		var self = $(this);
5175		self.defaults = {
5176			title: 'Our Recommended Reads'
5177		};
5178		if (!self.data('amSierraRecReads')) {
5179			self.data('amSierraRecReads', true);
5180			self.options = $.extend({}, self.defaults, options);
5181			self.hide();
5182			self.show = false;
5183			self.sections = [];
5184			var title = self.attr('data-title') || self.options.title;
5185			self.holder = $('<div class="ambl-holder"></div>').insertAfter(self);
5186			self.holder.append('<img tabindex="0" class="ambl-events-slideshow-button ' + self.attr('id') + ' ambl-events-slideshow-left" alt="left" title="left" caption="false" src="/images/next-left.png">');
5187			self.holder.append('<img tabindex="0" class="ambl-events-slideshow-button ' + self.attr('id') + ' ambl-events-slideshow-right" alt="right" title="right" caption="false" src="/images/next-right.png"></div>');
5188			self.catList = $('<div class="ambl-catlist"><div class="ambl-cat-title">' + title + '</div></div>').appendTo(self.holder);
5189			self.linkBase = self.attr('data-sierra-server');
5190			self.perPage = self.attr('data-count');
5191
5192			self.catList.on('click', '>span', function (event) {
5193				event.preventDefault();
5194				event.stopPropagation();
5195				self.holder.removeClass('open');
5196				showSet($(this).data('list'));
5197			}).on('mouseenter', function (event) {
5198				event.preventDefault();
5199				self.holder.addClass('open');
5200			}).on('mouseleave', function (event) {
5201				event.preventDefault();
5202				self.holder.removeClass('open');
5203			}).on('click', function (event) {
5204				event.preventDefault();
5205				self.holder.toggleClass('open');
5206			});
5207
5208			$('>li', self).each(function (sIndex, section) {
5209				self.sections[sIndex] = { title: $('span', section).text(), items: [] };
5210				$('ul>li', section).each(function (iIndex, item) {
5211					self.sections[sIndex].items[iIndex] = $(this).attr('data-bibid');
5212				});
5213			});
5214			$.each(self.sections, function (index, val) {
5215				$('<span></span>').text(val.title).data('list', val.items).appendTo(self.catList);
5216			});
5217			function showSet(items) {
5218				var w = 75 / self.perPage;
5219				var client = $('meta[name=client]').attr('content');
5220				var apiserver = $('meta[name=apiserver]').attr('content') || 'https://api.communico.co';
5221				$.getJSON(apiserver + '/v2/' + client + '/sierra/bibs/' + items.join(','), function (json, textStatus) {
5222					if (json.status !== 'success') return;
5223
5224					if (self.show) self.show.cycle('destroy').remove();
5225					self.show = $('<div class="ambl-show" data-cycle-fx="scrollHorz" data-cycle-log="false" data-cycle-next=".' + self.attr('id') + '.ambl-events-slideshow-right" data-cycle-pause-on-hover="true" data-cycle-prev=".' + self.attr('id') + '.ambl-events-slideshow-left" data-cycle-slides=">div" data-cycle-timeout="15000"></div>').appendTo(self.holder);
5226					var c = 0;
5227					var $section = $('<div></div>');
5228					$.each(json.data.entries, function (index, val) {
5229						if (c >= self.perPage) {
5230							c = 0;
5231							$section.appendTo(self.show);
5232							$section = $('<div></div>');
5233						}
5234						c++;
5235
5236						var server = index % 10;
5237						var coverUrl = 'https://covers' + server + '.communico.co/' + client + '/cover/?';
5238
5239						if (val.upcs[0]) {
5240							coverUrl += 'type=upc&id=' + val.upcs[0] + '&';
5241						} else if (val.isbns[0]) {
5242							coverUrl += 'type=isbn&id=' + val.isbns[0] + '&';
5243						}
5244
5245						coverUrl += 'title=' + encodeURIComponent(val.title || "No Cover Image Available");
5246
5247						$('<a target="_blank" href="' + self.linkBase.replace('{{bibid}}', val.id) + '"><img caption="false" title="' + val.title + '" alt="' + val.title + '" style="width:' + w + '%" src="' + coverUrl + '"></a>').appendTo($section);
5248					});
5249					$section.appendTo(self.show);
5250					self.show.cycle();
5251				});
5252			}
5253			if (self.sections.length < 2) {
5254				self.catList.hide();
5255			}
5256			showSet(self.sections[0].items);
5257		}
5258	});
5259	return this;
5260};
5261/************************************end  amSierraRecReads****************************************/
5262
5263/************************************start  amSirsiRecReads****************************************/
5264$.fn.amSirsiRecReads = function (options) {
5265	this.each(function (index, el) {
5266		var self = $(this);
5267		self.defaults = {
5268			title: 'Our Recommended Reads'
5269		};
5270		if (!self.data('amSirsiRecReads')) {
5271			self.data('amSirsiRecReads', true);
5272			self.options = $.extend({}, self.defaults, options);
5273			self.hide();
5274			self.show = false;
5275			self.sections = [];
5276			var title = self.attr('data-title') || self.options.title;
5277			self.holder = $('<div class="ambl-holder"></div>').insertAfter(self);
5278			self.holder.append('<img tabindex="0" class="ambl-events-slideshow-button ' + self.attr('id') + ' ambl-events-slideshow-left" alt="left" title="left" caption="false" src="/images/next-left.png">');
5279			self.holder.append('<img tabindex="0" class="ambl-events-slideshow-button ' + self.attr('id') + ' ambl-events-slideshow-right" alt="right" title="right" caption="false" src="/images/next-right.png"></div>');
5280			self.catList = $('<div class="ambl-catlist"><div class="ambl-cat-title">' + title + '</div></div>').appendTo(self.holder);
5281			self.linkBase = self.attr('data-sirsi-server');
5282			self.perPage = self.attr('data-count');
5283
5284			self.catList.on('click', '>span', function (event) {
5285				event.preventDefault();
5286				event.stopPropagation();
5287				self.holder.removeClass('open');
5288				showSet($(this).data('list'));
5289			}).on('mouseenter', function (event) {
5290				event.preventDefault();
5291				self.holder.addClass('open');
5292			}).on('mouseleave', function (event) {
5293				event.preventDefault();
5294				self.holder.removeClass('open');
5295			}).on('click', function (event) {
5296				event.preventDefault();
5297				self.holder.toggleClass('open');
5298			});
5299
5300			$('>li', self).each(function (sIndex, section) {
5301				self.sections[sIndex] = { title: $('span', section).text(), items: [] };
5302				$('ul>li', section).each(function (iIndex, item) {
5303					self.sections[sIndex].items[iIndex] = $(this).attr('data-bibid');
5304				});
5305			});
5306			$.each(self.sections, function (index, val) {
5307				$('<span></span>').text(val.title).data('list', val.items).appendTo(self.catList);
5308			});
5309			function showSet(items) {
5310				var w = 75 / self.perPage;
5311				var client = $('meta[name=client]').attr('content');
5312				var apiserver = $('meta[name=apiserver]').attr('content') || 'https://api.communico.co';
5313				$.getJSON(apiserver + '/v2/' + client + '/sirsidynix/bibs/' + items.join(','), function (json, textStatus) {
5314					if (json.status !== 'success') return;
5315
5316					if (self.show) self.show.cycle('destroy').remove();
5317					self.show = $('<div class="ambl-show" data-cycle-fx="scrollHorz" data-cycle-log="false" data-cycle-next=".' + self.attr('id') + '.ambl-events-slideshow-right" data-cycle-pause-on-hover="true" data-cycle-prev=".' + self.attr('id') + '.ambl-events-slideshow-left" data-cycle-slides=">div" data-cycle-timeout="15000"></div>').appendTo(self.holder);
5318					var c = 0;
5319					var $section = $('<div></div>');
5320					$.each(json.data, function (index, val) {
5321						if (c >= self.perPage) {
5322							c = 0;
5323							$section.appendTo(self.show);
5324							$section = $('<div></div>');
5325						}
5326						c++;
5327
5328						var server = index % 10;
5329						var coverUrl = 'https://covers' + server + '.communico.co/' + client + '/cover/?';
5330
5331						if (val.upc) {
5332							coverUrl += 'type=upc&id=' + val.upc + '&';
5333						} else if (val.isbns[0]) {
5334							coverUrl += 'type=isbn&id=' + val.isbns[0] + '&';
5335						}
5336
5337						coverUrl += 'title=' + encodeURIComponent(val.title || "No Cover Image Available");
5338
5339						var bibLink = self.linkBase + val.id + '/a';
5340						if (self.linkBase && self.linkBase.indexOf('{{bibid}}') > -1) {
5341							bibLink = self.linkBase.replace('{{bibid}}', val.id);
5342						}
5343						$('<a target="_blank" href="' + bibLink + '"><img caption="false" title="' + val.title + '" alt="' + val.title + '" style="width:' + w + '%" src="' + coverUrl + '"></a>').appendTo($section);
5344					});
5345					$section.appendTo(self.show);
5346					self.show.cycle();
5347				});
5348			}
5349			if (self.sections.length < 2) {
5350				self.catList.hide();
5351			}
5352			showSet(self.sections[0].items);
5353		}
5354	});
5355	return this;
5356};
5357/************************************end  amSirsiRecReads****************************************/
5358
5359function completeEventTransaction(ok, registrationCache) { // PayPal PayFlow
5360	$('#pp-iframe').remove();
5361	$('#PayPalForm').remove();
5362	var pppf = new PayPalPayFlow('', false, $("meta[name='client']").attr('content'));
5363
5364	// 'Thanks screen' for events with context.
5365	var thanksScreen = $('#reg-screen5', $('.events2-reg-stage'));
5366	var storage = window.sessionStorage || false;
5367	thanksScreen.empty();
5368
5369	if (ok) {
5370		pppf.showProcessingSuccessAnimation(thanksScreen, 'attend');
5371		setTimeout(function () {
5372			// clear the cart. We have success.
5373			var summary = pppf.showEventSummary(registrationCache);
5374			thanksScreen.empty().append(summary);
5375			//window.location.hash = "reserve";
5376		}, 2000);
5377	} else {
5378		pppf.showProcessingErrorAnimation(thanksScreen, 'attend');
5379		setTimeout(function () {
5380			//  We failed. Data has been cleared from the db.
5381			// Let's just leave the cart intact and go back to the rooms page.
5382			//window.location.hash = "#rooms/action/new";
5383			window.location.hash = "events";
5384		}, 5000);
5385	}
5386}
5387
5388function completeRoomTransaction(ok, bookings, transactionData) {
5389	$('#pp-iframe').remove();
5390	$('#PayPalForm').remove();
5391	//var $piframe = $('#pp-iframe');
5392	var pppf = new PayPalPayFlow('', false, $("meta[name='client']").attr('content'));
5393	$('.events2-reg-thanks-body').empty();
5394	var storage = window.sessionStorage || false;
5395	if (ok) {
5396		pppf.showProcessingSuccessAnimation($('.amnp-thanks-screen'), 'reserve');
5397		setTimeout(function () {
5398			// clear the cart. We have success.
5399			storage.removeItem('communicoReserveCart');
5400			pppf.showReserveSummary(bookings, transactionData);
5401			//window.location.hash = "reserve";
5402		}, 2000);
5403	} else {
5404		pppf.showProcessingErrorAnimation($('.amnp-thanks-screen'), 'reserve');
5405		setTimeout(function () {
5406			//  We failed. Data has been cleared from the db.
5407			// Let's just leave the cart intact and go back to the rooms page.
5408			//window.location.hash = "#rooms/action/new";
5409			window.location.hash = "reserve";
5410		}, 5000);
5411	}
5412}

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.