PageSourceSearch

https://www.isime.it/wp-content/plugins/booked/assets/js/functions.js?ver=2.4.4

js isime.it collected 2026-09-24 22:33:28 UTC 46,479 bytes, 1,479 lines download raw bytes

1// make it a global variable so other scripts can access it
2var booked_load_calendar_date_booking_options,
3	booked_appt_form_options,
4	bookedNewAppointment;
5
6;(function($, window, document, undefined) {
7
8	var $win = $(window);
9
10	$.fn.spin.presets.booked = {
11	 	lines: 10, // The number of lines to draw
12		length: 7, // The length of each line
13		width: 5, // The line thickness
14		radius: 11, // The radius of the inner circle
15		corners: 1, // Corner roundness (0..1)
16		rotate: 0, // The rotation offset
17		direction: 1, // 1: clockwise, -1: counterclockwise
18		color: '#555', // #rgb or #rrggbb or array of colors
19		speed: 1, // Rounds per second
20		trail: 60, // Afterglow percentage
21		shadow: false, // Whether to render a shadow
22		hwaccel: false, // Whether to use hardware acceleration
23		className: 'booked-spinner', // The CSS class to assign to the spinner
24		zIndex: 2e9, // The z-index (defaults to 2000000000)
25		top: '50%', // Top position relative to parent
26		left: '50%' // Left position relative to parent
27	}
28
29	$.fn.spin.presets.booked_top = {
30	 	lines: 11, // The number of lines to draw
31		length: 10, // The length of each line
32		width: 6, // The line thickness
33		radius: 15, // The radius of the inner circle
34		corners: 1, // Corner roundness (0..1)
35		rotate: 0, // The rotation offset
36		scale: 0.5,
37		direction: 1, // 1: clockwise, -1: counterclockwise
38		color: '#aaaaaa', // #rgb or #rrggbb or array of colors
39		speed: 1, // Rounds per second
40		trail: 60, // Afterglow percentage
41		shadow: false, // Whether to render a shadow
42		hwaccel: false, // Whether to use hardware acceleration
43		className: 'booked-spinner booked-spinner-top', // The CSS class to assign to the spinner
44		zIndex: 2e9, // The z-index (defaults to 2000000000)
45		top: '15px', // Top position relative to parent
46		left: '50%' // Left position relative to parent
47	}
48
49	$.fn.spin.presets.booked_white = {
50	 	lines: 13, // The number of lines to draw
51		length: 11, // The length of each line
52		width: 5, // The line thickness
53		radius: 18, // The radius of the inner circle
54		scale: 1,
55		corners: 1, // Corner roundness (0..1)
56		rotate: 0, // The rotation offset
57		direction: 1, // 1: clockwise, -1: counterclockwise
58		color: '#fff', // #rgb or #rrggbb or array of colors
59		speed: 1, // Rounds per second
60		trail: 60, // Afterglow percentage
61		shadow: false, // Whether to render a shadow
62		hwaccel: false, // Whether to use hardware acceleration
63		className: 'booked-spinner booked-white', // The CSS class to assign to the spinner
64		zIndex: 2e9, // The z-index (defaults to 2000000000)
65		top: '50%', // Top position relative to parent
66		left: '50%' // Left position relative to parent
67	}
68
69	// Adjust the calendar sizing when resizing the window
70	$win.on('resize', function(){
71
72		adjust_calendar_boxes();
73		resize_booked_modal();
74
75	});
76
77	$win.on('load', function() {
78
79		BookedTabs.Init();
80
81		var ajaxRequests = [];
82
83		// Adjust the calendar sizing on load
84		adjust_calendar_boxes();
85
86		$('.booked-calendar-wrap').each(function(){
87			var thisCalendar = $(this);
88			var calendar_month = thisCalendar.find('div.booked-calendar').attr('data-calendar-date');
89			thisCalendar.attr('data-default',calendar_month);
90			init_tooltips(thisCalendar);
91		});
92
93		$('.booked-list-view').each(function(){
94			var thisList = $(this);
95			var list_date = thisList.find('.booked-appt-list').attr('data-list-date');
96			thisList.attr('data-default',list_date);
97		});
98
99		bookedRemoveEmptyTRs();
100		init_appt_list_date_picker();
101
102		$('.booked_calendar_chooser').change(function(e){
103
104			e.preventDefault();
105
106			var $selector 			= $(this),
107				thisIsCalendar		= $selector.parents('.booked-calendarSwitcher').hasClass('calendar');
108
109			if (!thisIsCalendar){
110
111				var thisCalendarWrap	= $selector.parents('.booked-calendar-shortcode-wrap').find('.booked-list-view'),
112				thisDefaultDate			= thisCalendarWrap.attr('data-default'),
113				thisIsCalendar			= $selector.parents('.booked-calendarSwitcher').hasClass('calendar');
114
115				if (typeof thisDefaultDate == 'undefined'){ thisDefaultDate = false; }
116
117				thisCalendarWrap.addClass('booked-loading');
118
119				var args = {
120					'action'		: 'booked_appointment_list_date',
121					'nonce'			: booked_js_vars.nonce,
122					'date'			: thisDefaultDate,
123					'calendar_id'	: $selector.val()
124				};
125
126				$(document).trigger("booked-before-loading-appointment-list-booking-options");
127				thisCalendarWrap.spin('booked_top');
128
129				$.ajax({
130					url: booked_js_vars.ajax_url,
131					type: 'post',
132					data: args,
133					success: function( html ) {
134
135						thisCalendarWrap.html( html );
136
137						init_appt_list_date_picker();
138						setTimeout(function(){
139							thisCalendarWrap.removeClass('booked-loading');
140						},1);
141
142					}
143				});
144
145			} else {
146
147				var thisCalendarWrap 	= $selector.parents('.booked-calendar-shortcode-wrap').find('.booked-calendar-wrap'),
148				thisDefaultDate			= thisCalendarWrap.attr('data-default');
149				if (typeof thisDefaultDate == 'undefined'){ thisDefaultDate = false; }
150
151				var args = {
152					'action'		: 'booked_calendar_month',
153					'nonce'			: booked_js_vars.nonce,
154					'gotoMonth'		: thisDefaultDate,
155					'calendar_id'	: $selector.val()
156				};
157
158				savingState(true,thisCalendarWrap);
159
160				$.ajax({
161					url: booked_js_vars.ajax_url,
162					type: 'post',
163					data: args,
164					success: function( html ) {
165
166						thisCalendarWrap.html( html );
167
168						adjust_calendar_boxes();
169						bookedRemoveEmptyTRs();
170						init_tooltips(thisCalendarWrap);
171					 	$(window).trigger('booked-load-calendar', args, $selector );
172
173					}
174				});
175
176			}
177
178			return false;
179
180		});
181
182		// Calendar Next/Prev Click
183		$('body').on('click', '.booked-calendar-wrap .page-right, .booked-calendar-wrap .page-left, .booked-calendar-wrap .monthName a', function(e) {
184
185			e.preventDefault();
186
187			var $button 			= $(this),
188				gotoMonth			= $button.attr('data-goto'),
189				thisCalendarWrap 	= $button.parents('.booked-calendar-wrap'),
190				thisCalendarDefault = thisCalendarWrap.attr('data-default'),
191				calendar_id			= $button.parents('div.booked-calendar').attr('data-calendar-id');
192
193			if (typeof thisCalendarDefault == 'undefined'){ thisCalendarDefault = false; }
194
195			var args = {
196				'action'		: 'booked_calendar_month',
197				'nonce'			: booked_js_vars.nonce,
198				'gotoMonth'		: gotoMonth,
199				'calendar_id'	: calendar_id,
200				'force_default'	: thisCalendarDefault
201			};
202
203			savingState(true,thisCalendarWrap);
204
205			$.ajax({
206				url: booked_js_vars.ajax_url,
207				type: 'post',
208				data: args,
209				success: function( html ) {
210
211					thisCalendarWrap.html( html );
212
213					adjust_calendar_boxes();
214					bookedRemoveEmptyTRs();
215					init_tooltips(thisCalendarWrap);
216					$(window).trigger('booked-load-calendar', args, $button );
217
218				}
219			});
220
221			return false;
222
223		});
224
225		// Calendar Date Click
226		$('body').on('click', '.booked-calendar-wrap .bc-row.week .bc-col', function(e) {
227
228			e.preventDefault();
229
230			var $thisDate 				= $(this),
231				booked_calendar_table 	= $thisDate.parents('div.booked-calendar'),
232				$thisRow				= $thisDate.parent(),
233				date					= $thisDate.attr('data-date'),
234				calendar_id				= booked_calendar_table.attr('data-calendar-id'),
235				colspanSetting			= $thisRow.find('.bc-col').length;
236
237			if (!calendar_id){ calendar_id = 0; }
238
239			if ($thisDate.hasClass('blur') || $thisDate.hasClass('booked') && !booked_js_vars.publicAppointments || $thisDate.hasClass('prev-date')){
240
241				// Do nothing.
242
243			} else if ($thisDate.hasClass('active')){
244
245				$thisDate.removeClass('active');
246				$('.bc-row.entryBlock').remove();
247
248				var calendarHeight = booked_calendar_table.height();
249				booked_calendar_table.parent().height(calendarHeight);
250
251			} else {
252
253				$('.bc-row.week .bc-col').removeClass('active');
254				$thisDate.addClass('active');
255
256				$('.bc-row.entryBlock').remove();
257				$thisRow.after('<div class="bc-row entryBlock booked-loading"><div class="bc-col"></div></div>');
258				$('.bc-row.entryBlock').find('.bc-col').spin('booked');
259
260				booked_load_calendar_date_booking_options = {'action':'booked_calendar_date','nonce': booked_js_vars.nonce,'date':date,'calendar_id':calendar_id};
261				$(document).trigger("booked-before-loading-calendar-booking-options");
262
263				var calendarHeight = booked_calendar_table.height();
264				booked_calendar_table.parent().height(calendarHeight);
265
266				$.ajax({
267					url: booked_js_vars.ajax_url,
268					type: 'post',
269					data: booked_load_calendar_date_booking_options,
270					success: function( html ) {
271
272						$('.bc-row.entryBlock').find('.bc-col').html( html );
273
274						$('.bc-row.entryBlock').removeClass('booked-loading');
275						$('.bc-row.entryBlock').find('.booked-appt-list').fadeIn(300);
276						$('.bc-row.entryBlock').find('.booked-appt-list').addClass('shown');
277						adjust_calendar_boxes();
278
279					}
280				});
281
282			}
283
284			return;
285
286		});
287
288		// Appointment List Next/Prev Date Click
289		$('body').on('click', '.booked-list-view .booked-list-view-date-prev, .booked-list-view .booked-list-view-date-next', function(e) {
290
291			e.preventDefault();
292
293			var $thisLink 			= $(this),
294				date				= $thisLink.attr('data-date'),
295				thisList			= $thisLink.parents('.booked-list-view'),
296				defaultDate			= thisList.attr('data-default'),
297				calendar_id			= $thisLink.parents('.booked-list-view-nav').attr('data-calendar-id');
298
299			if (typeof defaultDate == 'undefined'){ defaultDate = false; }
300
301			if (!calendar_id){ calendar_id = 0; }
302
303			thisList.addClass('booked-loading');
304
305			var booked_load_list_view_date_booking_options = {
306				'action'		: 'booked_appointment_list_date',
307				'nonce'			: booked_js_vars.nonce,
308				'date'			: date,
309				'calendar_id'	: calendar_id,
310				'force_default'	: defaultDate
311			};
312
313			$(document).trigger("booked-before-loading-appointment-list-booking-options");
314			thisList.spin('booked_top');
315
316			$.ajax({
317				url: booked_js_vars.ajax_url,
318				type: 'post',
319				data: booked_load_list_view_date_booking_options,
320				success: function( html ) {
321
322					thisList.html( html );
323
324					init_appt_list_date_picker();
325					setTimeout(function(){
326						thisList.removeClass('booked-loading');
327					},1);
328
329				}
330			});
331
332			return false;
333
334		});
335
336		// New Appointment Click
337		bookedNewAppointment = function(e) {
338			e.preventDefault();
339
340			var $button 		= $(this),
341				title           = $button.attr('data-title'),
342				timeslot		= $button.attr('data-timeslot'),
343				date			= $button.attr('data-date'),
344				calendar_id		= $button.attr('data-calendar-id'),
345				$thisTimeslot	= $button.parents('.timeslot'),
346				is_list_view	= $button.parents('.booked-calendar-wrap').hasClass('booked-list-view');
347
348			if (typeof is_list_view != 'undefined' && is_list_view){
349				var new_calendar_id	= $button.parents('.booked-list-view').find('.booked-list-view-nav').attr('data-calendar-id');
350			} else {
351				var new_calendar_id	= $button.parents('div.booked-calendar').attr('data-calendar-id');
352			}
353			calendar_id = new_calendar_id ? new_calendar_id : calendar_id;
354
355			booked_appt_form_options = {'action':'booked_new_appointment_form','nonce': booked_js_vars.nonce,'date':date,'timeslot':timeslot,'calendar_id':calendar_id,'title':title};
356			$(document).trigger("booked-before-loading-booking-form");
357
358			create_booked_modal();
359			setTimeout(function(){
360
361				$.ajax({
362					url: booked_js_vars.ajax_url,
363					type: 'post',
364					data: booked_appt_form_options,
365					success: function( html ) {
366
367						$('.bm-window').html( html );
368
369						var bookedModal = $('.booked-modal');
370						var bmWindow = bookedModal.find('.bm-window');
371						bmWindow.css({'visibility':'hidden'});
372						bookedModal.removeClass('bm-loading');
373						$(document).trigger("booked-on-new-app");
374						resize_booked_modal();
375						bmWindow.hide();
376						$('.booked-modal .bm-overlay').find('.booked-spinner').remove();
377
378						setTimeout(function(){
379							bmWindow.css({'visibility':'visible'});
380							bmWindow.show();
381						},50);
382
383					}
384				});
385
386			},100);
387
388			return false;
389		}
390		$('body').on('click', '.booked-calendar-wrap button.new-appt', bookedNewAppointment);
391
392		// Profile Tabs
393		var profileTabs = $('.booked-tabs');
394
395		if (!profileTabs.find('li.active').length){
396			profileTabs.find('li:first-child').addClass("active");
397		}
398
399		if (profileTabs.length){
400			$('.booked-tab-content').hide();
401			var activeTab = profileTabs.find('.active > a').attr('href');
402			activeTab = activeTab.split('#');
403			activeTab = activeTab[1];
404			$('#profile-'+activeTab).show();
405
406			profileTabs.find('li > a').on('click', function(e) {
407
408				e.preventDefault();
409				$('.booked-tab-content').hide();
410				profileTabs.find('li').removeClass('active');
411
412				$(this).parent().addClass('active');
413				var activeTab = $(this).attr('href');
414				activeTab = activeTab.split('#');
415				activeTab = activeTab[1];
416
417				$('#profile-'+activeTab).show();
418				return false;
419
420			});
421		}
422
423		// Show Additional Information
424		$('body').on('click', '.booked-profile-appt-list .booked-show-cf', function(e) {
425
426			e.preventDefault();
427			var hiddenBlock = $(this).parent().find('.cf-meta-values-hidden');
428
429			if(hiddenBlock.is(':visible')){
430				hiddenBlock.hide();
431				$(this).removeClass('booked-cf-active');
432			} else {
433				hiddenBlock.show();
434				$(this).addClass('booked-cf-active');
435			}
436
437			return false;
438
439		});
440
441		// Check Login/Registration/Forgot Password forms before Submitting
442		if ($('#loginform').length){
443			$('#loginform input[type="submit"]').on('click',function(e) {
444				if ($('#loginform input[name="log"]').val() && $('#loginform input[name="pwd"]').val()){
445					$('#loginform .booked-custom-error').hide();
446				} else {
447					if ( $('#loginform').parents('.booked-form-wrap').length ){
448						e.preventDefault();
449						$('#loginform').parents('.booked-form-wrap').find('.booked-custom-error').fadeOut(200).fadeIn(200);
450					}
451				}
452			});
453		}
454
455		if ($('#profile-forgot').length){
456			$('#profile-forgot input[type="submit"]').on('click',function(e) {
457				if ($('#profile-forgot input[name="user_login"]').val()){
458					$('#profile-forgot .booked-custom-error').hide();
459				} else {
460					e.preventDefault();
461					$('#profile-forgot').find('.booked-custom-error').fadeOut(200).fadeIn(200);
462				}
463			});
464		}
465
466		// Custom Upload Field
467		if ($('.booked-upload-wrap').length){
468
469			$('.booked-upload-wrap input[type=file]').on('change',function(){
470
471				var fileName = $(this).val();
472				$(this).parent().find('span').html(fileName);
473				$(this).parent().addClass('hasFile');
474
475			});
476
477		}
478
479		// Delete Appointment
480		$('body').on('click', '.booked-profile-appt-list .appt-block .cancel', function(e) {
481
482			e.preventDefault();
483
484			var $button 		= $(this),
485				$thisParent		= $button.parents('.appt-block'),
486				appt_id			= $thisParent.attr('data-appt-id');
487
488			confirm_delete = confirm(booked_js_vars.i18n_confirm_appt_delete);
489			if (confirm_delete == true){
490
491				var currentApptCount = parseInt($('.booked-profile-appt-list').find('h4').find('span.count').html());
492				currentApptCount = parseInt(currentApptCount - 1);
493				if (currentApptCount < 1){
494					$('.booked-profile-appt-list').find('h4').find('span.count').html('0');
495					$('.no-appts-message').slideDown('fast');
496				} else {
497					$('.booked-profile-appt-list').find('h4').find('span.count').html(currentApptCount);
498				}
499
500				$('.appt-block').animate({'opacity':0.4},0);
501
502	  			$thisParent.slideUp('fast',function(){
503					$(this).remove();
504				});
505
506				$.ajax({
507					'url' 		: booked_js_vars.ajax_url,
508					'method' 	: 'post',
509					'data'		: {
510						'action'     	: 'booked_cancel_appt',
511						'nonce'			: booked_js_vars.nonce,
512						'appt_id'     	: appt_id
513					},
514					success: function(data) {
515						$('.appt-block').animate({'opacity':1},150);
516					}
517				});
518
519			}
520
521			return false;
522
523		});
524
525		$('body').on('touchstart click','.bm-overlay, .bm-window .close, .booked-form .cancel',function(e){
526			e.preventDefault();
527			close_booked_modal();
528			return false;
529		});
530
531		$('body')
532		.on('focusin', '.booked-form input', function() {
533			if(this.title==this.value) {
534				$(this).addClass('hasContent');
535				this.value = '';
536			}
537		}).on('focusout', '.booked-form input', function(){
538			if(this.value==='') {
539				$(this).removeClass('hasContent');
540				this.value = this.title;
541			}
542		});
543
544		$('body').on('change','.booked-form input',function(){
545
546			var condition = $(this).attr('data-condition'),
547				thisVal = $(this).val();
548
549			if (condition && $('.condition-block').length) {
550				$('.condition-block.'+condition).hide();
551				$('#condition-'+thisVal).fadeIn(200);
552				resize_booked_modal();
553			}
554
555		});
556
557		// Perform AJAX login on form submit
558	    $('body').on('submit','form#ajaxlogin', function(e){
559		    e.preventDefault();
560
561	        $('form#ajaxlogin p.status').show().html('<i class="fa-solid fa-circle-notch fa-spin"></i>&nbsp;&nbsp;&nbsp;' + booked_js_vars.i18n_please_wait);
562	        resize_booked_modal();
563
564	        var $this = $(this),
565	        	date = $this.data('date'),
566	        	title = $this.data('title'),
567	        	timeslot = $this.data('timeslot'),
568	        	calendar_id = $this.data('calendar-id');
569
570	        $.ajax({
571		        type	: 'post',
572				url 	: booked_js_vars.ajax_url,
573				data	: $('form#ajaxlogin').serialize(),
574				success	: function(data) {
575					if (data == 'success'){
576
577						// close the modal box
578						close_booked_modal();
579
580						// reopen the modal box
581						var $button = $( '<button data-title="' + title + '" data-timeslot="' + timeslot + '" data-date="' + date + '" data-calendar-id="' + calendar_id + '"></button>' );
582						$button.on( 'click', window.bookedNewAppointment );
583						$button.triggerHandler( 'click' );
584						$button.unbind( 'click', window.bookedNewAppointment );
585						$button.detach();
586
587					} else {
588						$('form#ajaxlogin p.status').show().html('<i class="fa-solid fa-triangle-exclamation" style="color:#E35656"></i>&nbsp;&nbsp;&nbsp;' + booked_js_vars.i18n_wrong_username_pass);
589						resize_booked_modal();
590					}
591	            }
592	        });
593	        e.preventDefault();
594	    });
595
596	    $('body').on('click','.booked-forgot-password',function(e){
597
598			e.preventDefault();
599			$('#ajaxlogin').hide();
600			$('#ajaxforgot').show();
601
602			resize_booked_modal();
603
604	    });
605
606	     $('body').on('click','.booked-forgot-goback',function(e){
607
608			e.preventDefault();
609			$('#ajaxlogin').show();
610			$('#ajaxforgot').hide();
611
612			resize_booked_modal();
613
614	    });
615
616	    // Perform AJAX login on form submit
617
618	    $('body').on('submit','form#ajaxforgot', function(e){
619		    e.preventDefault();
620
621	        $('form#ajaxforgot p.status').show().html('<i class="fa-solid fa-circle-notch fa-spin"></i>&nbsp;&nbsp;&nbsp;' + booked_js_vars.i18n_please_wait);
622	        resize_booked_modal();
623
624	        var $this = $(this);
625
626	        $.ajax({
627		        type	: 'post',
628				url 	: booked_js_vars.ajax_url,
629				data	: $('form#ajaxforgot').serialize(),
630				success	: function(data) {
631					if (data == 'success'){
632
633						e.preventDefault();
634						$('#ajaxlogin').show();
635						$('#ajaxforgot').hide();
636
637						$('form#ajaxlogin p.status').show().html('<i class="fa-solid fa-check" style="color:#56c477"></i>&nbsp;&nbsp;&nbsp;' + booked_js_vars.i18n_password_reset);
638						resize_booked_modal();
639
640					} else {
641
642						//console.log(data);
643						$('form#ajaxforgot p.status').show().html('<i class="fa-solid fa-triangle-exclamation" style="color:#E35656"></i>&nbsp;&nbsp;&nbsp;' + booked_js_vars.i18n_password_reset_error);
644						resize_booked_modal();
645
646					}
647	            }
648	        });
649	        e.preventDefault();
650	    });
651
652
653		// Submit the "Request Appointment" Form
654		$('body').on('click','.booked-form input#submit-request-appointment',function(e){
655
656			$('form#newAppointmentForm p.status').show().html('<i class="fa-solid fa-circle-notch fa-spin"></i>&nbsp;&nbsp;&nbsp;' + booked_js_vars.i18n_please_wait);
657	        resize_booked_modal();
658
659			e.preventDefault();
660
661			var customerType        = $('#newAppointmentForm input[name=customer_type]').val(),
662				customerID          = $('#newAppointmentForm input[name=user_id]').val(),
663				name                = $('#newAppointmentForm input[name=booked_appt_name]').val(),
664				surname             = $('#newAppointmentForm input[name=booked_appt_surname]').val(),
665				surnameActive		= $('#newAppointmentForm input[name=booked_appt_surname]').length,
666				guest_name          = $('#newAppointmentForm input[name=guest_name]').val(),
667				guest_surname      	= $('#newAppointmentForm input[name=guest_surname]').val(),
668				guest_surnameActive = $('#newAppointmentForm input[name=guest_surname]').length,
669				guest_email			= $('#newAppointmentForm input[name=guest_email]').val(),
670				guest_emailActive 	= $('#newAppointmentForm input[name=guest_email]').length,
671				email               = $('#newAppointmentForm input[name=booked_appt_email]').val(),
672				password            = $('#newAppointmentForm input[name=booked_appt_password]').val(),
673				showRequiredError   = false,
674				ajaxRequests        = [];
675
676			$(this).parents('.booked-form').find('input,textarea,select').each(function(i,field){
677
678				var required = $(this).attr('required');
679
680				if (required && $(field).attr('type') == 'hidden'){
681					var fieldParts = $(field).attr('name');
682					fieldParts = fieldParts.split('---');
683					fieldName = fieldParts[0];
684					fieldNumber = fieldParts[1].split('___');
685					fieldNumber = fieldNumber[0];
686
687					if (fieldName == 'radio-buttons-label'){
688						var radioValue = false;
689						$('input:radio[name="single-radio-button---'+fieldNumber+'[]"]:checked').each(function(){
690							if ($(this).val()){
691								radioValue = $(this).val();
692							}
693						});
694						if (!radioValue){
695							showRequiredError = true;
696						}
697					} else if (fieldName == 'checkboxes-label'){
698						var checkboxValue = false;
699						$('input:checkbox[name="single-checkbox---'+fieldNumber+'[]"]:checked').each(function(){
700							if ($(this).val()){
701								checkboxValue = $(this).val();
702							}
703						});
704						if (!checkboxValue){
705							showRequiredError = true;
706						}
707					}
708
709				} else if (required && $(field).attr('type') != 'hidden' && $(field).val() == ''){
710		            showRequiredError = true;
711		        }
712
713		    });
714
715		    if (showRequiredError) {
716			    $('form#newAppointmentForm p.status').show().html('<i class="fa-solid fa-triangle-exclamation" style="color:#E35656"></i>&nbsp;&nbsp;&nbsp;' + booked_js_vars.i18n_fill_out_required_fields);
717				resize_booked_modal();
718			    return false;
719		    }
720
721			if ( customerType == 'new' && !name || customerType == 'new' && surnameActive && !surname || customerType == 'new' && !email || customerType == 'new' && !password ) {
722				$('form#newAppointmentForm p.status').show().html('<i class="fa-solid fa-triangle-exclamation" style="color:#E35656"></i>&nbsp;&nbsp;&nbsp;' + booked_js_vars.i18n_appt_required_fields);
723				resize_booked_modal();
724				return false;
725			}
726
727			if ( customerType == 'guest' && !guest_name || customerType == 'guest' && guest_emailActive && !guest_email || customerType == 'guest' && guest_surnameActive && !guest_surname ){
728				$('form#newAppointmentForm p.status').show().html('<i class="fa-solid fa-triangle-exclamation" style="color:#E35656"></i>&nbsp;&nbsp;&nbsp;' + booked_js_vars.i18n_appt_required_fields_guest);
729				resize_booked_modal();
730				return false;
731			}
732
733			if (customerType == 'current' && customerID ||
734				customerType == 'guest' && guest_name && !guest_surnameActive && !guest_emailActive ||
735				customerType == 'guest' && guest_name && guest_surnameActive && guest_surname && !guest_emailActive ||
736				customerType == 'guest' && guest_name && guest_emailActive && guest_email && !guest_surnameActive ||
737				customerType == 'guest' && guest_name && guest_emailActive && guest_email && guest_surnameActive && guest_surname ) {
738
739			    SubmitRequestAppointment.currentUserOrGuest();
740
741			}
742
743			if (customerType == 'new' && name && email && password) {
744				if ( !surnameActive || surnameActive && surname ){
745					SubmitRequestAppointment.newUser();
746				}
747			}
748
749		});
750
751		var SubmitRequestAppointment = {
752
753			formSelector: '#newAppointmentForm',
754			formBtnRequestSelector: '.booked-form input#submit-request-appointment',
755			formStatusSelector: 'p.status',
756			formSubmitBtnSelector: '#submit-request-appointment',
757
758			apptContainerSelector: '.booked-appointment-details',
759
760			baseFields: 	[ 'guest_name','guest_surname','guest_email','action', 'customer_type', 'user_id' ],
761			apptFields: 	[ 'appoinment', 'calendar_id', 'title', 'date', 'timestamp', 'timeslot' ],
762			userFields: 	[ 'booked_appt_name','booked_appt_surname','booked_appt_email', 'booked_appt_password' ],
763			captchaFields: 	[ 'captcha_word', 'captcha_code' ],
764
765			currentApptIndex: false,
766			currentApptCounter: false,
767			hasAnyErrors: false,
768
769			currentUserOrGuest: function() {
770				var total_appts = SubmitRequestAppointment._totalAppts();
771
772				if ( ! total_appts ) {
773					return;
774				}
775
776				SubmitRequestAppointment._showLoadingMessage();
777				SubmitRequestAppointment._resetDefaultValues();
778
779				var data = SubmitRequestAppointment._getBaseData();
780
781				SubmitRequestAppointment.currentApptIndex = 0;
782				SubmitRequestAppointment.currentApptCounter = 1;
783				SubmitRequestAppointment._doRequestAppointment( data, total_appts );
784
785			},
786
787			// pretty much the same as SubmitRequestAppointment.currentUserOrGuest(), however, it include the user name, email and password
788			newUser: function() {
789				var total_appts = SubmitRequestAppointment._totalAppts();
790
791				if ( ! total_appts ) {
792					return;
793				}
794
795				SubmitRequestAppointment._showLoadingMessage();
796				SubmitRequestAppointment._resetDefaultValues();
797
798				var data = SubmitRequestAppointment._getBaseData();
799
800				// when there are more than one appointment, we need to make the registration request first and then loop the appointments
801				if ( total_appts > 1 ) {
802					var data_obj_with_no_reference = null;
803					data_obj_with_no_reference = $.extend( true, {}, data );
804					data_obj_with_no_reference = SubmitRequestAppointment._addUserRegistrationData( data_obj_with_no_reference );
805					SubmitRequestAppointment._requestUserRegistration( data_obj_with_no_reference );
806
807					data.customer_type = 'current';
808				} else {
809					// add user registration fields values
810					data = SubmitRequestAppointment._addUserRegistrationData( data );
811				}
812
813				SubmitRequestAppointment.currentApptIndex = 0;
814				SubmitRequestAppointment._doRequestAppointment( data, total_appts );
815			},
816
817			_doRequestAppointment: function( data, total_appts ) {
818
819				var appt_fields = SubmitRequestAppointment.apptFields;
820
821				// for the first item only
822				if ( SubmitRequestAppointment.currentApptIndex === 0 ) {
823					SubmitRequestAppointment._hideCancelBtn();
824					SubmitRequestAppointment._disableSubmitBtn();
825					SubmitRequestAppointment.hasAnyErrors = false;
826				}
827				// <------end
828
829				var data_obj_with_no_reference = $.extend( true, {}, data );
830
831				// add the appointment fields to the data
832				for (var i = 0; i < appt_fields.length; i++) {
833					data_obj_with_no_reference[ appt_fields[i] ] = SubmitRequestAppointment._getFieldVal( appt_fields[i], SubmitRequestAppointment.currentApptIndex );
834				}
835
836				var calendar_id = SubmitRequestAppointment._getFieldVal( 'calendar_id', SubmitRequestAppointment.currentApptIndex );
837				data_obj_with_no_reference = SubmitRequestAppointment._addCustomFieldsData( data_obj_with_no_reference, calendar_id );
838
839				var $appt = SubmitRequestAppointment._getApptElement( SubmitRequestAppointment.currentApptIndex );
840
841				if ( ! $appt.hasClass('skip') ) {
842					$.ajax({
843						type    : 'post',
844						url     : booked_js_vars.ajax_url,
845						data    : data_obj_with_no_reference,
846						success	: function( response ) {
847
848							//SubmitRequestAppointment._enableSubmitBtn();
849							//SubmitRequestAppointment._showCancelBtn();
850
851							//console.log(response);
852							//return;
853
854							SubmitRequestAppointment._requestAppointmentResponseHandler( response );
855							SubmitRequestAppointment.currentApptIndex++;
856
857							setTimeout( function() {
858								if ( SubmitRequestAppointment.currentApptCounter === total_appts ) {
859									// for the last item only
860									if ( ! SubmitRequestAppointment.hasAnyErrors ) {
861										SubmitRequestAppointment._onAfterRequestAppointment();
862									} else {
863										SubmitRequestAppointment._enableSubmitBtn();
864										SubmitRequestAppointment._showCancelBtn();
865									}
866									// <------end
867								} else {
868									SubmitRequestAppointment.currentApptCounter++;
869									SubmitRequestAppointment._doRequestAppointment( data, total_appts );
870								}
871							}, 100 );
872						}
873					});
874				} else {
875					SubmitRequestAppointment.currentApptIndex++;
876					SubmitRequestAppointment.currentApptCounter++;
877					SubmitRequestAppointment._doRequestAppointment( data, total_appts, SubmitRequestAppointment.currentApptIndex );
878				}
879			},
880
881			_totalAppts: function() {
882				return $(SubmitRequestAppointment.formSelector + ' input[name="appoinment[]"]').length;
883			},
884
885			_getBaseData: function() {
886				var data = {},
887					fields = SubmitRequestAppointment.baseFields;
888
889				// set up the base form data
890				for ( var i = 0; i < fields.length; i++ ) {
891					data[ fields[i] ] = SubmitRequestAppointment._getFieldVal( fields[i] );
892				}
893
894				data['nonce'] = booked_js_vars.nonce;
895				data['is_fe_form'] = true;
896				data['total_appts'] = SubmitRequestAppointment._totalAppts();
897
898				return data;
899			},
900
901			_getFieldVal: function( field_name, field_index ) {
902				var field_name = typeof field_name === 'undefined' ? '' : field_name,
903					field_index = typeof field_index === 'undefined' ? false : field_index,
904					selector = SubmitRequestAppointment.formSelector + ' ';
905
906				if ( field_index === false ) {
907					selector += ' [name=' + field_name + ']';
908					return $( selector ).val();
909				}
910
911				selector += ' [name="' + field_name + '[]"]';
912				return $( selector ).eq( field_index ).val();
913			},
914
915			_resetDefaultValues: function() {
916				 $('.booked-form input').each(function(){
917					var thisVal = $(this).val(),
918						thisDefault = $(this).attr('title');
919
920					if ( thisDefault == thisVal ){
921						$(this).val('');
922					}
923				});
924			},
925
926			_resetToDefaultValues: function() {
927				$('.booked-form input').each(function(){
928					var thisVal = $(this).val(),
929						thisDefault = $(this).attr('title');
930
931					if ( ! thisVal ){
932						$(this).val( thisDefault );
933					}
934				});
935			},
936
937			_addUserRegistrationData: function( data ) {
938				// populate the user data
939				$.each( SubmitRequestAppointment.userFields, function( index, field_name ) {
940					data[ field_name ] = SubmitRequestAppointment._getFieldVal( field_name );
941				} );
942
943				// populate captcha data if available
944				$.each( SubmitRequestAppointment.captchaFields, function( index, field_name ) {
945					var field_value = SubmitRequestAppointment._getFieldVal( field_name );
946
947					if ( ! field_value ) {
948						return;
949					}
950
951					data[ field_name ] = field_value;
952				} );
953
954				return data;
955			},
956
957			_addCustomFieldsData: function( data, calendar_id ) {
958				var custom_fields_data = $('.cf-block [name]')
959					.filter( function( index ) {
960						var $this = $(this);
961						return parseInt($this.data('calendar-id')) === parseInt(calendar_id) && $this.attr('name').match(/---\d+/g);
962					} )
963					.each( function( index ) {
964						var $this = $(this),
965							name = $this.attr('name'),
966							value = $this.val(),
967							type = $this.attr('type');
968
969						if ( ! value ) {
970							return;
971						}
972
973						if ( ! name.match(/checkbox|radio+/g) ) {
974							data[ name ] = value;
975							return;
976						}
977
978						if ( name.match(/radio+/g) && $this.is(':checked') ) {
979							data[ name ] = value;
980							return;
981						}
982
983						if ( ! name.match(/radio+/g) && typeof data[ name ] === 'undefined' || ! name.match(/radio+/g) && data[ name ].constructor !== Array ) {
984							data[ name ] = [];
985						}
986
987						if ( ! $this.is(':checked') ) {
988							return;
989						}
990
991						data[ name ].push( value );
992					} );
993
994				return data;
995			},
996
997			_requestUserRegistration: function( base_data, appt_index ) {
998				$.ajax({
999					type    : 'post',
1000					url     : booked_js_vars.ajax_url,
1001					data    : base_data,
1002					async   : false,
1003					success	: function( response ) {
1004						SubmitRequestAppointment._requestUserRegistrationResponseHandler( response );
1005					}
1006				});
1007			},
1008
1009			_requestUserRegistrationResponseHandler: function( response ) {
1010				var response_parts = response.split('###'),
1011					data_result = response_parts[0].substr( response_parts[0].length - 5 );
1012
1013				if ( data_result === 'error' ) {
1014					// do something on registration failure
1015					return;
1016				}
1017
1018				// do something on successful registration
1019			},
1020
1021			_requestAppointment: function( response ) {
1022				SubmitRequestAppointment._requestAppointmentResponseHandler( response );
1023			},
1024
1025			_requestAppointmentResponseHandler: function( response ) {
1026				var response_parts = response.split('###'),
1027					data_result = response_parts[0].substr( response_parts[0].length - 5 );
1028
1029				if ( data_result === 'error' ) {
1030					SubmitRequestAppointment._requestAppointmentOnError( response_parts );
1031					return;
1032				}
1033
1034				SubmitRequestAppointment._requestAppointmentOnSuccess( response_parts );
1035			},
1036
1037			_requestAppointmentOnError: function( response_parts ) {
1038				var $apptEl = SubmitRequestAppointment._getApptElement();
1039
1040				$(document).trigger("booked-on-requested-appt-error",[$apptEl]);
1041
1042				SubmitRequestAppointment._highlightAppt();
1043
1044				SubmitRequestAppointment._setStatusMsg( response_parts[1] );
1045
1046				SubmitRequestAppointment.hasAnyErrors = true;
1047
1048				resize_booked_modal();
1049			},
1050
1051			_requestAppointmentOnSuccess: function( response_parts ) {
1052				var $apptEl = SubmitRequestAppointment._getApptElement();
1053
1054				$(document).trigger("booked-on-requested-appt-success",[$apptEl]);
1055
1056				SubmitRequestAppointment._unhighlightAppt();
1057			},
1058
1059			_onAfterRequestAppointment: function() {
1060				var redirectObj = { redirect : false };
1061				var redirect = $(document).trigger("booked-on-requested-appointment",[redirectObj]);
1062
1063				if ( redirectObj.redirect ) {
1064					return;
1065				}
1066
1067				if ( booked_js_vars.profilePage ) {
1068					window.location = booked_js_vars.profilePage;
1069					return;
1070				}
1071
1072				SubmitRequestAppointment._reloadApptsList();
1073				SubmitRequestAppointment._reloadCalendarTable();
1074			},
1075
1076			_setStatusMsg: function( msg ) {
1077				var form_status_selector = SubmitRequestAppointment.formSelector + ' ' + SubmitRequestAppointment.formStatusSelector;
1078				$( form_status_selector ).show().html( '<i class="fa-solid fa-triangle-exclamation" style="color:#E35656"></i>&nbsp;&nbsp;&nbsp;' + msg );
1079			},
1080
1081			_getApptElement: function( appt_index ) {
1082				var appt_index = typeof appt_index === 'undefined' ? SubmitRequestAppointment.currentApptIndex : appt_index,
1083					appt_cnt_selector = SubmitRequestAppointment.formSelector + ' ' + SubmitRequestAppointment.apptContainerSelector;
1084
1085				return $( appt_cnt_selector ).eq( appt_index );
1086			},
1087
1088			_highlightAppt: function( msg ) {
1089				var $apptEl = SubmitRequestAppointment._getApptElement();
1090
1091				if ( ! $apptEl.length ) {
1092					return;
1093				}
1094
1095				$apptEl.addClass('has-error');
1096			},
1097
1098			_unhighlightAppt: function( msg ) {
1099				var $apptEl = SubmitRequestAppointment._getApptElement();
1100
1101				if ( ! $apptEl.length ) {
1102					return;
1103				}
1104
1105				$apptEl.removeClass('has-error').addClass('skip');
1106			},
1107
1108			_enableSubmitBtn: function() {
1109				var btn_selector = SubmitRequestAppointment.formSelector + ' ' + SubmitRequestAppointment.formSubmitBtnSelector;
1110				$( btn_selector ).attr( 'disabled', false );
1111			},
1112
1113			_disableSubmitBtn: function() {
1114				var btn_selector = SubmitRequestAppointment.formSelector + ' ' + SubmitRequestAppointment.formSubmitBtnSelector;
1115				$( btn_selector ).attr( 'disabled', true );
1116			},
1117
1118			_showCancelBtn: function() {
1119				$( SubmitRequestAppointment.formSelector ).find('button.cancel').show();
1120			},
1121
1122			_hideCancelBtn: function() {
1123				$( SubmitRequestAppointment.formSelector ).find('button.cancel').hide();
1124			},
1125
1126			_showLoadingMessage: function() {
1127				$('form#newAppointmentForm p.status').show().html('<i class="fa-solid fa-circle-notch fa-spin"></i>&nbsp;&nbsp;&nbsp;' + booked_js_vars.i18n_please_wait);
1128			},
1129
1130			_reloadApptsList: function() {
1131				if ( ! $('.booked-appt-list').length ){
1132					return;
1133				}
1134
1135				$('.booked-appt-list').each( function() {
1136					var $thisApptList  = $(this),
1137						date          = $thisApptList.attr('data-list-date'),
1138						thisList      = $thisApptList.parents('.booked-list-view'),
1139						defaultDate   = thisList.attr('data-default'),
1140						calendar_id   = parseInt($thisApptList.find('.booked-list-view-nav').attr('data-calendar-id')) || 0;
1141
1142					defaultDate = typeof defaultDate === 'undefined' ? false : defaultDate;
1143					calendar_id = calendar_id ? calendar_id : 0;
1144
1145					thisList.addClass('booked-loading');
1146
1147					var booked_load_list_view_date_booking_options = {
1148						'action'		: 'booked_appointment_list_date',
1149						'nonce'			: booked_js_vars.nonce,
1150						'date'			: date,
1151						'calendar_id'	: calendar_id,
1152						'force_default'	: defaultDate
1153					};
1154
1155					$(document).trigger("booked-before-loading-appointment-list-booking-options");
1156					thisList.spin('booked_top');
1157
1158					$.ajax({
1159						url: booked_js_vars.ajax_url,
1160						type: 'post',
1161						data: booked_load_list_view_date_booking_options,
1162						success: function( html ) {
1163							thisList.html( html );
1164
1165							close_booked_modal();
1166							init_appt_list_date_picker();
1167							setTimeout(function(){
1168								thisList.removeClass('booked-loading');
1169							},1);
1170						}
1171					});
1172				});
1173			},
1174
1175			_reloadCalendarTable: function() {
1176				if ( ! $('.bc-col.active').length ) {
1177					return;
1178				}
1179
1180				var $activeTD = $('.bc-col.active'),
1181					activeDate = $activeTD.attr('data-date'),
1182					calendar_id = parseInt( $activeTD.parents('table').data('calendar-id') ) || 0;
1183
1184				booked_load_calendar_date_booking_options = { 'action':'booked_calendar_date','nonce': booked_js_vars.nonce,'date':activeDate, 'calendar_id':calendar_id };
1185				$(document).trigger("booked-before-loading-calendar-booking-options");
1186
1187				$.ajax({
1188					url: booked_js_vars.ajax_url,
1189					type: 'post',
1190					data: booked_load_calendar_date_booking_options,
1191					success: function( html ) {
1192
1193						$('.bc-row.entryBlock').find('.bc-col').html( html );
1194
1195						close_booked_modal();
1196						$('.bc-row.entryBlock').removeClass('booked-loading');
1197						$('.bc-row.entryBlock').find('.booked-appt-list').hide().fadeIn(300);
1198						$('.bc-row.entryBlock').find('.booked-appt-list').addClass('shown');
1199						adjust_calendar_boxes();
1200					}
1201				});
1202			}
1203		}
1204	});
1205
1206	function bookedRemoveEmptyTRs(){
1207		$('div.booked-calendar').find('.bc-row.week').each(function(){
1208			if ($(this).children().length == 0){
1209				$(this).remove();
1210			}
1211		});
1212	}
1213
1214	// Saving state updater
1215	function savingState(show,limit_to){
1216
1217		show = typeof show !== 'undefined' ? show : true;
1218		limit_to = typeof limit_to !== 'undefined' ? limit_to : false;
1219
1220		if (limit_to){
1221
1222			var $savingStateDIV = limit_to.find('li.active .savingState, .topSavingState.savingState, .calendarSavingState');
1223			var $stuffToHide = limit_to.find('.monthName');
1224			var $stuffToTransparent = limit_to.find('div.booked-calendar .bc-body');
1225
1226		} else {
1227
1228			var $savingStateDIV = $('li.active .savingState, .topSavingState.savingState, .calendarSavingState');
1229			var $stuffToHide = $('.monthName');
1230			var $stuffToTransparent = $('div.booked-calendar .bc-body');
1231
1232		}
1233
1234		if (show){
1235			$savingStateDIV.fadeIn(200);
1236			$stuffToHide.hide();
1237			$stuffToTransparent.animate({'opacity':0.2},100);
1238		} else {
1239			$savingStateDIV.hide();
1240			$stuffToHide.show();
1241			$stuffToTransparent.animate({'opacity':1},0);
1242		}
1243
1244	}
1245
1246	$(document).ajaxStop(function() {
1247		savingState(false);
1248	});
1249
1250	function init_appt_list_date_picker(){
1251
1252		$('.booked_list_date_picker').each(function(){
1253			var thisDatePicker = $(this);
1254			var minDateVal = thisDatePicker.parents('.booked-appt-list').attr('data-min-date');
1255			var maxDateVal = thisDatePicker.parents('.booked-appt-list').attr('data-max-date');
1256			if (typeof minDateVal == 'undefined'){ var minDateVal = thisDatePicker.attr('data-min-date'); }
1257
1258			thisDatePicker.datepicker({
1259		        dateFormat: 'yy-mm-dd',
1260		        minDate: minDateVal,
1261		        maxDate: maxDateVal,
1262		        showAnim: false,
1263		        beforeShow: function(input, inst) {
1264					$('#ui-datepicker-div').removeClass();
1265					$('#ui-datepicker-div').addClass('booked_custom_date_picker');
1266			    },
1267			    onClose: function(dateText){
1268					$('.booked_list_date_picker_trigger').removeClass('booked-dp-active');
1269			    },
1270			    onSelect: function(dateText){
1271
1272				   	var thisInput 			= $(this),
1273						date				= dateText,
1274						thisList			= thisInput.parents('.booked-list-view'),
1275						defaultDate			= thisList.attr('data-default'),
1276						calendar_id			= thisInput.parents('.booked-list-view-nav').attr('data-calendar-id');
1277
1278					if (typeof defaultDate == 'undefined'){ defaultDate = false; }
1279
1280					if (!calendar_id){ calendar_id = 0; }
1281					thisList.addClass('booked-loading');
1282
1283					var booked_load_list_view_date_booking_options = {
1284						'action'		: 'booked_appointment_list_date',
1285						'nonce'			: booked_js_vars.nonce,
1286						'date'			: date,
1287						'calendar_id'	: calendar_id,
1288						'force_default'	: defaultDate
1289					};
1290
1291					$(document).trigger("booked-before-loading-appointment-list-booking-options");
1292					thisList.spin('booked_top');
1293
1294					$.ajax({
1295						url: booked_js_vars.ajax_url,
1296						type: 'post',
1297						data: booked_load_list_view_date_booking_options,
1298						success: function( html ) {
1299
1300							thisList.html( html );
1301
1302							init_appt_list_date_picker();
1303							setTimeout(function(){
1304								thisList.removeClass('booked-loading');
1305							},1);
1306
1307						}
1308					});
1309
1310					return false;
1311			    }
1312		    });
1313
1314		});
1315
1316		$('body').on('click','.booked_list_date_picker_trigger',function(e){
1317			e.preventDefault();
1318			if (!$(this).hasClass('booked-dp-active')){
1319				$(this).addClass('booked-dp-active');
1320				$(this).parents('.booked-appt-list').find('.booked_list_date_picker').datepicker('show');
1321			}
1322
1323	    });
1324
1325	}
1326
1327	var BookedTabs = {
1328		bookingModalSelector: '.booked-modal',
1329		tabSelector: '.booked-tabs',
1330		tabNavSelector: '.booked-tabs-nav span',
1331		tabCntSelector: '.booked-tabs-cnt',
1332
1333		Init: function() {
1334			$(document).on( 'click', this.tabNavSelector, this.tabsNav );
1335		},
1336
1337		tabsNav: function( event ) {
1338			event.preventDefault();
1339
1340			BookedTabs.switchToTab( $(this) );
1341			BookedTabs.maybeResizeBookingModal();
1342		},
1343
1344		switchToTab: function( tab_nav_item ) {
1345			var $nav_item = tab_nav_item,
1346				tab_cnt_class = '.' + $nav_item.data('tab-cnt'),
1347				$tabs_container = $nav_item.parents( BookedTabs.tabSelector );
1348
1349			$nav_item
1350				.addClass( 'active' )
1351				.siblings()
1352				.removeClass( 'active' )
1353
1354			$tabs_container
1355				.find( BookedTabs.tabCntSelector + ' ' + tab_cnt_class )
1356				.addClass( 'active' )
1357				.siblings()
1358				.removeClass( 'active' );
1359		},
1360
1361		maybeResizeBookingModal: function() {
1362			if ( ! $(BookedTabs.bookingModalSelector).length ) {
1363				return;
1364			}
1365
1366			resize_booked_modal();
1367		}
1368	}
1369
1370})(jQuery, window, document);
1371
1372// Create Booked Modal
1373function create_booked_modal(){
1374	var windowHeight = jQuery(window).height();
1375	var windowWidth = jQuery(window).width();
1376	if (windowWidth > 720){
1377		var maxModalHeight = windowHeight - 295;
1378	} else {
1379		var maxModalHeight = windowHeight;
1380	}
1381
1382	jQuery('body input, body textarea, body select').blur();
1383	jQuery('body').addClass('booked-noScroll');
1384	jQuery('<div class="booked-modal bm-loading"><div class="bm-overlay"></div><div class="bm-window"><div style="height:100px"></div></div></div>').appendTo('body');
1385	jQuery('.booked-modal .bm-overlay').spin('booked_white');
1386	jQuery('.booked-modal .bm-window').css({'max-height':maxModalHeight+'px'});
1387}
1388
1389var previousRealModalHeight = 100;
1390
1391function resize_booked_modal(){
1392
1393	var windowHeight = jQuery(window).height();
1394	var windowWidth = jQuery(window).width();
1395
1396	var common43 = 43;
1397
1398	if (jQuery('.booked-modal .bm-window .booked-scrollable').length){
1399		var realModalHeight = jQuery('.booked-modal .bm-window .booked-scrollable')[0].scrollHeight;
1400
1401		if (realModalHeight < 100){
1402			realModalHeight = previousRealModalHeight;
1403		} else {
1404			previousRealModalHeight = realModalHeight;
1405		}
1406
1407	} else {
1408		var realModalHeight = 0;
1409	}
1410	var minimumWindowHeight = realModalHeight + common43 + common43;
1411	var modalScrollableHeight = realModalHeight - common43;
1412	var maxModalHeight;
1413	var maxFormHeight;
1414
1415	if (windowHeight < minimumWindowHeight){
1416		modalScrollableHeight = windowHeight - common43 - common43;
1417	} else {
1418		modalScrollableHeight = realModalHeight;
1419	}
1420
1421	if (windowWidth > 720){
1422		maxModalHeight = modalScrollableHeight - 25;
1423		maxFormHeight = maxModalHeight - 15;
1424		var modalNegMargin = (maxModalHeight + 78) / 2;
1425	} else {
1426		maxModalHeight = windowHeight - common43;
1427		maxFormHeight = maxModalHeight - 60;
1428		var modalNegMargin = (maxModalHeight) / 2;
1429	}
1430
1431	jQuery('.booked-modal').css({'margin-top':'-'+modalNegMargin+'px'});
1432	jQuery('.booked-modal .bm-window').css({'max-height':maxModalHeight+'px'});
1433	jQuery('.booked-modal .bm-window .booked-scrollable').css({'max-height':maxFormHeight+'px'});
1434
1435}
1436
1437function close_booked_modal(){
1438	var modal = jQuery('.booked-modal');
1439	modal.fadeOut(200);
1440	modal.addClass('bm-closing');
1441	jQuery('body').removeClass('booked-noScroll');
1442	setTimeout(function(){
1443		modal.remove();
1444	},300);
1445}
1446
1447function init_tooltips(container){
1448	jQuery('.tooltipster').tooltipster({
1449		theme: 		'tooltipster-light',
1450		animation:	'grow',
1451		speed:		200,
1452		delay: 		50,
1453		offsetY:	-15
1454	});
1455}
1456
1457// Function to adjust calendar sizing
1458function adjust_calendar_boxes(){
1459	jQuery('div.booked-calendar').each(function(){
1460
1461		var windowWidth = jQuery(window).width();
1462		var smallCalendar = jQuery(this).parents('.booked-calendar-wrap').hasClass('small');
1463		var boxesWidth = jQuery(this).find('.bc-body .bc-row.week .bc-col').width();
1464		var calendarHeight = jQuery(this).height();
1465		boxesHeight = boxesWidth * 1;
1466		jQuery(this).find('.bc-body .bc-row.week .bc-col').height(boxesHeight);
1467		jQuery(this).find('.bc-body .bc-row.week .bc-col .date').css('line-height',boxesHeight+'px');
1468		jQuery(this).find('.bc-body .bc-row.week .bc-col .date .number').css('line-height',boxesHeight+'px');
1469		if (smallCalendar || windowWidth < 720){
1470			jQuery(this).find('.bc-body .bc-row.week .bc-col .date .number').css('line-height',boxesHeight+'px');
1471		} else {
1472			jQuery(this).find('.bc-body .bc-row.week .bc-col .date .number').css('line-height','');
1473		}
1474
1475		var calendarHeight = jQuery(this).height();
1476		jQuery(this).parent().height(calendarHeight);
1477
1478	});
1479}

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.