PageSourceSearch

https://www.holycrossct.org/js/frontend/form-builder.js

js holycrossct.org collected 2026-10-09 21:39:05 UTC 62,413 bytes, 1,693 lines download raw bytes

1// Multi Step Form Vars (also used for payment calcs/handling when applicable)
2var form = $('#main-submission-form');
3var is_multi_step_form = ($(form).hasClass('multi-step')?1:0);
4var cur_step = 1;
5var cur_idx = cur_step-1;
6var submit_button = $(form).find('#submit-button');
7var require_form_captcha = 1;
8
9if($('.phone').length) {
10	$.when(add_js(shared_root+'/js/jquery/jquery.autotab/jquery.autotab-1.1b.js')).done(function() {
11		$("input.phone").closest('.field-wrap').addClass('phone-field-wrap');
12		$('.phone-field-wrap').each(function() {
13			$(this).find('input').autotab_magic().autotab_filter("numeric");
14		});
15	});
16} 
17
18if($('.datepicker').length) {
19	add_css(shared_root+'/css/smoothness/jquery-ui-1.8.custom.css');
20}
21
22if($('#map_canvas').length || $('.google-address-field').length) {
23	$.when(add_js('//maps.googleapis.com/maps/api/js?key=AIzaSyBhu5ibJC_Df3aYWZW_ryElSDtrQbvg9HA&libraries=places')).done(function() {
24		if($('.google-address-field').length) {
25			$.when(
26				add_js(shared_root+'/js/json/json2.js')
27			).done(function() {
28				add_js(shared_root+'/js/google-address-lookup-crm.js',1);
29			});
30		}
31
32		if($('#map_canvas').length) {
33			var map;
34			var marker;
35
36			function initialize() {
37				var myOptions = {
38					zoom: 14,
39					center: new google.maps.LatLng($('#map_canvas').attr('data-latitude'),$('#map_canvas').attr('data-longitude')),
40					mapTypeId: google.maps.MapTypeId.ROADMAP
41				}
42				map = new google.maps.Map(document.getElementById("map_canvas"), myOptions);
43
44				marker = new google.maps.Marker({
45					position: new google.maps.LatLng($('#map_canvas').attr('data-latitude'),$('#map_canvas').attr('data-longitude')),
46					map: map
47				});
48			}
49
50			initialize();
51
52			$("#go").click(function() {
53				var start = document.getElementById("start").value;
54				var end = document.getElementById("end").value;
55
56				window.open('https://www.google.com/maps/dir/'+encodeURIComponent(start)+'/'+encodeURIComponent(end),'_blank');
57				return false;
58			});
59
60			$("#start").keydown(function(e) {
61				if(e.keyCode==13) {
62					$("#go").click();
63				}
64			});
65		}
66	});
67}
68
69
70/* ----------------------------------------------------------------------------------------------------------------------- */
71/* Post-Submit Error Auto-Scroll to Form --------------------------------------------------------------------------------- */
72/* ----------------------------------------------------------------------------------------------------------------------- */
73if($('.bad-alert').length) {
74	var form_top = $('#main-submission-form').offset().top;
75
76	var header;
77	if($('#header').length) {
78		header = $('#header');
79	} else if($('.header').length) {
80		header = $('.header');
81	}
82	if(header && $(header).length && ($(header).css('position') == 'absolute' || $(header).css('position') == 'fixed')) {
83		form_top -= $(header).height();
84	}
85	if(form_top) {
86		$('body,html').animate({'scrollTop':form_top+'px'},'fast','easeInOutQuad');
87	}
88}
89
90
91/* ---------------------------------------------------------------------------------------------------------------------- */
92/* Discount Code Handling ----------------------------------------------------------------------------------------------- */
93/* ---------------------------------------------------------------------------------------------------------------------- */
94var discount_type = 'amount'; // or percentage
95var discount_amount = 0;
96$('#apply-discount-code-button').click(function() {
97	var discount_code = $('#discount-code-field').val();
98	discount_type = 'amount';
99	discount_amount = 0;
100
101	if(discount_code) {
102		$.ajax({
103			type: "POST",
104			url: "?check_discount_code="+discount_code,
105			success: function(json,textStatus) {
106				if(json == '0') {
107					$('#discount-code-message').html('<strong class="red">This discount code is not valid.</strong>');
108
109				} else if(json == '-1') {
110					$('#discount-code-message').html('<strong class="red">You have made too many requests, please wait a while before trying again.</strong>');
111	
112				} else {
113					var data = jQuery.parseJSON(json);
114					$('#discount-code-message').html('<strong class="green" id="discount-amount" data-type="'+data.type+'" data-amount="'+data.amount+'">Valid Code! A discount of '+(data.type=='percentage'?data.amount+'%':'$'+parseFloat(data.amount).toFixed(2))+' will be applied.');
115					discount_type = data.type;
116					discount_amount = data.amount;
117				}				
118				calculate_fees();
119			}
120		});
121	} else {
122		$('#discount-code-message').html('<strong class="red">This discount code is not valid.</strong>');
123		calculate_fees();
124	}
125
126	return false;
127});
128
129
130/* ----------------------------------------------------------------------------------------------------------------------- */
131/* Payment Handling ------------------------------------------------------------------------------------------------------ */
132/* ----------------------------------------------------------------------------------------------------------------------- */
133/*
134if($('#card-element').length) {
135	var form = $("#main-submission-form");
136
137	$(form).submit(function() {
138		if($('#per-month').length) {
139			if(confirm('Are you sure you want to submit this form and setup an automatically recurring monthly payment?')) {
140				$('body').append('<div id="form-loading"></div>');
141				return true;
142			}
143
144			return false;
145
146		} else {
147			$('body').append('<div id="form-loading"></div>');
148		}
149	});
150}
151*/
152
153if($('select[name=payment_method]').find('option').length <= 1) {
154	$("#payment-method-field-wrap").hide();
155}
156
157$("#payment-method").on('change',function() {
158	$("#stripe-fields").hide().find('.required').addClass('payment-conditionally-required').removeClass('required');
159	$('#authdotnet-cc-fields, #authdotnet-ach-fields, #card-zip-field-wrap, #bluesnap-cc-fields, #clover-cc-fields').hide().find('.required').addClass('payment-conditionally-required').removeClass('required');
160	$("#form-section-captcha").show();
161	require_form_captcha = 1;
162	if($('.captcha-wrap').closest('.field-wrap').length) $('.captcha-wrap').closest('.field-wrap').show();
163	if(is_multi_step_form) {
164		show_or_hide_multi_step_submit_button()
165	} else {
166		$(submit_button).val("Submit").show();
167	}
168	$("#non-card-method-field-wrap").hide();
169	if($('#paypal-button-container').length) $('#paypal-button-container').hide();
170	if($('#field-wrap-allow-customer-to-pay-for-fees').length) $('#field-wrap-allow-customer-to-pay-for-fees').hide();
171	
172	var amount = get_payment_amount();
173
174	if(amount) {
175		if($(this).val() == "stripe") {
176			$("#stripe-fields").stop(1,1).fadeIn("fast").find('.payment-conditionally-required').addClass('required');
177			// $("#form-section-captcha").hide();
178			// require_form_captcha = 0;
179			// if($('.captcha-wrap').closest('.field-wrap').length) $('.captcha-wrap').closest('.field-wrap').hide();
180			if($('#field-wrap-allow-customer-to-pay-for-fees').length) $('#field-wrap-allow-customer-to-pay-for-fees').show();
181
182		} else if ($(this).val() == "paypal") {
183			$(submit_button).val("Submit & Continue to PayPal");
184
185		} else if ($(this).val() == "paypal_business") {
186			$(submit_button).hide();
187			// $("#form-section-captcha").hide();
188			// require_form_captcha = 0;
189			// if($('.captcha-wrap').closest('.field-wrap').length) $('.captcha-wrap').closest('.field-wrap').hide();
190			if(!$('#paypal_json').length) {
191				$('#main-submission-form').append('<input type="hidden" name="paypal_funding_source" id="paypal_funding_source"></textarea>');
192				$('#main-submission-form').append('<textarea name="paypal_json" id="paypal_json" style="display: none;"></textarea>');
193				$('#main-submission-form #form-section-payment-details').append('<div class="paypal-button-container" id="paypal-button-container"></div>');
194				do_paypal_business_handling();
195			}
196			$('#paypal-button-container').show();
197
198		} else if ($(this).val() == "authdotnet") {
199			$("#authdotnet-cc-fields").stop(1,1).fadeIn("fast").find('.payment-conditionally-required').addClass('required');
200			if($('#field-wrap-allow-customer-to-pay-for-fees').length) $('#field-wrap-allow-customer-to-pay-for-fees').show();
201			// $("#form-section-captcha").hide();
202			// require_form_captcha = 0;
203			// if($('.captcha-wrap').closest('.field-wrap').length) $('.captcha-wrap').closest('.field-wrap').hide();
204			$('#card-zip-field-wrap').hide().find('.required').addClass('payment-conditionally-required').removeClass('required');
205
206			
207		} else if ($(this).val() == "authdotnet_ach") {
208			$("#authdotnet-ach-fields").stop(1,1).fadeIn("fast").find('.payment-conditionally-required').addClass('required');;
209			// $("#form-section-captcha").hide();
210			// require_form_captcha = 0;
211			// if($('.captcha-wrap').closest('.field-wrap').length) $('.captcha-wrap').closest('.field-wrap').hide();
212		
213		} else if ($(this).val() == "bluesnap") {
214			$("#bluesnap-cc-fields").stop(1,1).fadeIn("fast").find('.payment-conditionally-required').addClass('required');
215			if($('#field-wrap-allow-customer-to-pay-for-fees').length) $('#field-wrap-allow-customer-to-pay-for-fees').show();
216			$('#card-zip-field-wrap').show().find('.payment-conditionally-required').removeClass('payment-conditionally-required').addClass('required');
217		
218		} else if ($(this).val() == "clover") {
219			$("#clover-cc-fields").stop(1,1).fadeIn("fast").find('.payment-conditionally-required').addClass('required');
220			if($('#field-wrap-allow-customer-to-pay-for-fees').length) $('#field-wrap-allow-customer-to-pay-for-fees').show();
221
222		} else if ($(this).val() == '') {
223			// $(submit_button).hide();
224			// $("#form-section-captcha").hide();
225			// if($('.captcha-wrap').closest('.field-wrap').length) $('.captcha-wrap').closest('.field-wrap').hide();
226
227		} else {
228			$("#non-card-method-field-wrap").show();
229		}
230	}
231}).change();
232
233$('#main-submission-form').submit(function() {
234	if($('#payment-method').length && $('#payment-method').val() == 'authdotnet') {
235		$('body').append('<div id="form-loading"></div>');
236	}
237});
238
239var original_base_amount = $('#amount').attr('data-base-amount');
240
241if($('#payment-frequency-selection').length) {
242	var payment_methods_html = $('#payment-method').html();
243
244	$('.payment-frequency-selection-radio').change(function() {
245		check_recurring_payment_frequency();
246	});
247	check_recurring_payment_frequency();
248
249	function check_recurring_payment_frequency() {
250		$('#amount').attr('data-base-amount',original_base_amount);
251		
252		if($('.payment-frequency-selection-radio:checked').length && $('.payment-frequency-selection-radio:checked').val() == 1) {
253			$('.field-wrap-how-often, .field-wrap-recurring-payment-start-date, .field-wrap-recurring-payment-end-date').show();
254			$('#payment-method option').each(function() {
255				if(
256					$(this).val() != 'stripe' &&
257					$(this).val() != 'authdotnet' &&
258					$(this).val() != 'bluesnap' &&
259					$(this).val() != 'cash' &&
260					$(this).val() != 'check' &&
261					$(this).val() != 'po' &&
262					$(this).val() != 'account'
263				) {
264					$(this).remove();
265				}
266			}).change();
267
268			$('#recurring_payment_interval').change();
269		} else {
270			var cur_payment_method_val = $('#payment-method').val();
271			$('#payment-method').html(payment_methods_html).val(cur_payment_method_val).change();
272			$('.field-wrap-how-often, .field-wrap-recurring-payment-start-date, .field-wrap-recurring-payment-end-date').hide();
273		}
274
275		calculate_fees();
276	}
277}
278
279$('#recurring_payment_interval').change(function() {
280	if($('.payment-frequency-selection-radio:checked').length && $('.payment-frequency-selection-radio:checked').val() == 1) {
281		var selected_interval = $(this).val();
282		if($('#recurring_payment_interval option[value="'+selected_interval+'"]').attr('data-price-adjustment')) {
283			$('#amount').attr('data-base-amount',$('#recurring_payment_interval option[value="'+selected_interval+'"]').attr('data-price-adjustment'));
284		}
285	} else {
286		$('#amount').attr('data-base-amount',original_base_amount);
287	}
288
289	$('#amount').html('$'+parseFloat($('#amount').attr('data-base-amount')).toLocaleString('us', {minimumFractionDigits: 2, maximumFractionDigits: 2}));
290	calculate_fees();
291}).change();
292
293$('.check-routing-number-helper-link').click(function() {
294	showSoSimpleOverlay($('#check-routing-number-helper-content').html());
295	return false;
296});
297
298
299/* ----------------------------------------------------------------------------------------------------------------------- */
300/* BlueSnap Payment Handling --------------------------------------------------------------------------------------------- */
301/* ----------------------------------------------------------------------------------------------------------------------- */
302$(window).on('load',function() {
303	if($('#bluesnap-cc-fields').length) {
304		$.ajax({
305			type: "GET",
306			url: '?get_bluesnap_token=1&no_template=1',
307			success: function(bluesnap_token,textStatus) {
308				function changeImpactedElement(tagId, removeClass, addClass) {
309					removeClass = removeClass || "";
310					addClass = addClass || "";
311					$("[data-bluesnap=" + tagId + "]")
312						.removeClass(removeClass)
313						.addClass(addClass);
314				}
315				var bluesnap_card_url = {
316					"AMEX": "https://files.readme.io/97e7acc-Amex.png", 
317					"DINERS": "https://files.readme.io/8c73810-Diners_Club.png",
318					"DISCOVER": "https://files.readme.io/caea86d-Discover.png",
319					"JCB": "https://files.readme.io/e076aed-JCB.png",
320					"MASTERCARD": "https://files.readme.io/5b7b3de-Mastercard.png",
321					"VISA": "https://files.readme.io/9018c4f-Visa.png"
322				}; 
323
324				var bsObj = {
325					token: bluesnap_token, 
326					onFieldEventHandler: {
327						onFocus: function(tagId) {
328							changeImpactedElement(tagId, "hosted-field-valid hosted-field-invalid", "hosted-field-focus"); 
329						},
330						onBlur: function(tagId) {
331							changeImpactedElement(tagId, "hosted-field-focus"); 
332						},
333						onError: function(tagId, errorCode, errorDescription, eventOrigin) {
334							changeImpactedElement(tagId, "hosted-field-valid hosted-field-focus", "hosted-field-invalid");     
335							$("#" + tagId + "-help").removeClass('helper-text-green').text(errorCode + " - " + errorDescription + " - " + eventOrigin); 
336						},
337						onType: function(tagId, cardType, cardData) {
338							$("#card-logo > img").attr("src", bluesnap_card_url[cardType]);
339							if (null != cardData) {
340								$("#" + tagId + "-help").addClass('helper-text-green').text(JSON.stringify(cardData));
341							}
342						},
343						onValid: function(tagId) {
344							changeImpactedElement(tagId, "hosted-field-focus hosted-field-invalid", "hosted-field-valid"); 
345							$("#" + tagId + "-help").text(""); 
346						}
347					},
348					style: {
349						// Styling all inputs
350						"input": {
351                            "border-style": "solid",
352                            "border-width": "1px",
353                            "border-color": "#808080",
354                            "position": "static",
355                            "font-size": "16px",
356                            "font-family": "Helvetica Neue,Helvetica,Arial,sans-serif",
357                            "line-height": "1.42857143",
358                            "color": "#555",
359                            "padding": "5px",
360                            "height": "auto !important",
361                            "width": "220px !important",
362						},
363						"#cvv": {
364							"width": "100px !important"			
365						},
366						"#exp": {
367							"width": "100px !important"			
368						},
369						":focus": {
370							"color": "#555"
371						}
372					},
373					ccnPlaceHolder: "",
374					cvvPlaceHolder: "",
375					expPlaceHolder: "MM / YY"
376				}
377
378				$(document).ready(function() {
379					bluesnap.hostedPaymentFieldsCreate(bsObj); 
380				});
381
382				// Handle form submission.
383				var form = document.getElementById("main-submission-form");
384				form.addEventListener("submit", function(event) {
385					var amount = get_payment_amount();
386
387					if(amount > 0) {
388						if($("#payment-method").val() == "bluesnap") {
389							var bluesnap_error = 0;
390							$('.bluesnap-hosted-field-wrap').each(function() {
391								if(!$(this).hasClass('hosted-field-valid')) {
392									bluesnap_error = 1;
393								}
394							});
395
396							if(bluesnap_error) {
397								showAlert('Some of your billing information is invalid.','bad');
398
399							} else {
400								$("body").append('<div id="form-loading"></div>');
401								do_blue_snap_initial_submit();
402							}
403
404							event.preventDefault();							
405						}
406					}
407				});
408
409				function do_blue_snap_initial_submit() {
410					bluesnap.hostedPaymentFieldsSubmitData( 
411						function(callback) {
412							if (null != callback.error) {
413								showAlert("There was a problem processing your card information.","bad");
414								/*
415								var errorArray = callback.error;
416								for (i in errorArray) {
417									$("#" + errorArray[i].tagId + "-help").text(errorArray[i].errorCode + " - " + errorArray[i].errorDescription); 
418								}*/
419							} else {
420								// var cardData = callback.cardData;
421
422								var form = $('#main-submission-form');
423
424								// Insert the token ID into the form so it gets submitted to the server
425								// Add Stripe Token to hidden input
426								var hiddenInput = document.createElement("input");
427								hiddenInput.setAttribute("type", "hidden");
428								hiddenInput.setAttribute("name", "bluesnap_token");
429								hiddenInput.setAttribute("value", bluesnap_token);
430								$(form).append(hiddenInput);
431
432								// Submit form
433								$(form).submit();
434							}
435						}
436					);
437				}
438			}
439		});
440	}
441});
442
443
444/* ----------------------------------------------------------------------------------------------------------------------- */
445/* Clover Payment Handling ----------------------------------------------------------------------------------------------- */
446/* ----------------------------------------------------------------------------------------------------------------------- */
447$(window).on('load',function() {
448	if($('#clover-cc-fields').length) {
449		$.ajax({
450			type: "GET",
451			url: '?get_clover_api_key=1&no_template=1',
452			success: function(clover_key,textStatus) {
453				if(clover_key == 'ERROR') {
454					console.log('Error getting Clover API Key');
455					$("#payment-method option[value='clover']").remove();
456					$('#payment-method').change();
457					$('#clover-cc-fields').hide();
458
459				} else {
460					var clover = new Clover(clover_key);
461					var clover_elements = clover.elements();
462
463					var clover_styles = {
464						body: {
465							fontFamily: "Roboto, Open Sans, sans-serif",
466							fontSize: "16px",
467						},
468						input: {
469							border: "1px solid #ccc",
470							fontSize: "16px",
471							padding: "10px",
472							height: "auto",
473							width: "auto",
474						}
475					};
476
477					var clover_form = document.getElementById("main-submission-form");
478					var cardNumber = clover_elements.create("CARD_NUMBER", clover_styles);
479					var cardDate = clover_elements.create("CARD_DATE", clover_styles);
480					var cardCvv = clover_elements.create("CARD_CVV", clover_styles);
481					var cardPostalCode = clover_elements.create("CARD_POSTAL_CODE", clover_styles);
482					
483					cardNumber.mount("#card-number");
484					cardDate.mount("#card-date");
485					cardCvv.mount("#card-cvv");
486					cardPostalCode.mount("#card-postal-code");
487					
488					/*
489					var cardResponse = document.getElementById("card-response");
490					var displayCardNumberError = document.getElementById("card-number-errors");
491					var displayCardDateError = document.getElementById("card-date-errors");
492					var displayCardCvvError = document.getElementById("card-cvv-errors");
493					var displayCardPostalCodeError = document.getElementById("card-postal-code-errors");
494
495					cardNumber.addEventListener("change", function(event) {
496						console.log(`cardNumber changed ${JSON.stringify(event)}`);
497					});
498
499					cardNumber.addEventListener("blur", function(event) {
500						console.log(`cardNumber blur ${JSON.stringify(event)}`);
501					});
502
503					cardDate.addEventListener("change", function(event) {
504						console.log(`cardDate changed ${JSON.stringify(event)}`);
505					});
506
507					cardDate.addEventListener("blur", function(event) {
508						console.log(`cardDate blur ${JSON.stringify(event)}`);
509					});
510
511					cardCvv.addEventListener("change", function(event) {
512						console.log(`cardCvv changed ${JSON.stringify(event)}`);
513					});
514
515					cardCvv.addEventListener("blur", function(event) {
516						console.log(`cardCvv blur ${JSON.stringify(event)}`);
517					});
518
519					cardPostalCode.addEventListener("change", function(event) {
520						console.log(`cardPostalCode changed ${JSON.stringify(event)}`);
521					});
522
523					cardPostalCode.addEventListener("blur", function(event) {
524						console.log(`cardPostalCode blur ${JSON.stringify(event)}`);
525					});
526					*/
527
528					clover_form.addEventListener("submit", function(event) {
529						var amount = get_payment_amount();
530
531						if(amount > 0) {
532							if($("#payment-method").val() == "clover") {
533								$("body").append('<div id="form-loading"></div>');
534								
535								clover.createToken().then(function(result) {
536									var errors = do_form_validation($(form).find('.required').not('.conditionally-required'),require_captcha=1,do_not_show_errors=1);
537
538									if (result.errors) {
539										Object.values(result.errors).forEach(function (value) {
540											errors += (errors?'<br />':'')+value;
541										});
542										showAlert(errors,'bad');
543										$("#form-loading").remove();
544		
545									} else {			
546										// Insert the token ID into the form so it gets submitted to the server					
547										var clover_form = document.getElementById("main-submission-form");
548										var hiddenInput = document.createElement("input");
549										hiddenInput.setAttribute("type", "hidden");
550										hiddenInput.setAttribute("name", "cloverToken");
551										hiddenInput.setAttribute("value", result.token);
552										clover_form.appendChild(hiddenInput);
553										clover_form.submit();
554									}
555								});
556								
557								event.preventDefault();							
558							}
559						}
560					});			
561				}
562			}
563		});
564	}
565});
566
567
568/* ----------------------------------------------------------------------------------------------------------------------- */
569/* Signature Pad Handling ------------------------------------------------------------------------------------------------ */
570/* ----------------------------------------------------------------------------------------------------------------------- */
571if($('.m-signature-pad').length) {
572	var form_builder_signature_cached_widths = [];
573	var form_builder_signature_cached_images = [];
574	var form_builder_signature_pads = [];
575	$.when(add_js(shared_root+'/js/signature-pad/signature_pad.js')).done(function() {
576		var i = 0;
577		$('.m-signature-pad').each(function() {
578			var wrapper = $(this);
579				var clearButton = $(wrapper).find('.clear'),
580				canvas = $(wrapper).find('canvas')[0],
581				signature = $(wrapper).find('textarea.signature');
582			
583			if($(signature).val()) {
584				var ctx = canvas.getContext("2d");
585				var image = new Image();
586				image.onload = function() {
587					ctx.drawImage(image, 0, 0);
588				};
589				image.src = $(signature).val();
590			}
591
592			var ratio =  Math.max(window.devicePixelRatio || 1, 1);
593			canvas.width = canvas.offsetWidth * ratio;
594			canvas.height = canvas.offsetHeight * ratio;
595			canvas.getContext("2d").scale(ratio, ratio);
596			form_builder_signature_cached_widths[i] = canvas.offsetWidth;
597			window.onresize = resizeSignatureCanvas;
598
599			form_builder_signature_pads[i] = new SignaturePad(canvas,{
600				onEnd: function() {
601					$(signature).val(canvas.toDataURL()).change();
602				}
603			});
604
605			var signaturePad = form_builder_signature_pads[i];
606
607			$(clearButton).on('click',function() {
608				signaturePad.clear();
609				$(signature).val('').change();
610			});
611
612			i++;
613		});
614	});
615
616	// Adjust canvas coordinate space taking into account pixel ratio,
617	// to make it look crisp on mobile devices.
618	// This also causes canvas to be cleared.
619	function resizeSignatureCanvas() {
620		var i = 0;
621		$('.m-signature-pad').each(function() {
622			var wrapper = $(this),
623				canvas = $(wrapper).find('canvas')[0];
624
625			if(canvas.offsetWidth !== form_builder_signature_cached_widths[i]){ //add
626				if (typeof form_builder_signature_pads[i] != 'undefined') {
627					form_builder_signature_cached_images[i] = form_builder_signature_pads[i].toDataURL("image/png");
628				}
629				form_builder_signature_cached_widths[i] = canvas.offsetWidth;
630
631				// When zoomed out to less than 100%, for some very strange reason,
632				// some browsers report devicePixelRatio as less than 1
633				// and only part of the canvas is cleared then.
634				var ratio =  Math.max(window.devicePixelRatio || 1, 1);
635				canvas.width = canvas.offsetWidth * ratio;
636				canvas.height = canvas.offsetHeight * ratio;
637				canvas.getContext("2d").scale(ratio, ratio);
638				if (typeof form_builder_signature_pads[i] != 'undefined') {
639					form_builder_signature_pads[i].fromDataURL(form_builder_signature_cached_images[i]); // add
640				}
641			}
642
643			i++;
644		});
645	}
646}
647
648
649/* ----------------------------------------------------------------------------------------------------------------------- */
650/* Chosen Dropdown Replace Handling (for multi-selects) ------------------------------------------------------------------ */
651/* ----------------------------------------------------------------------------------------------------------------------- */
652var chosen_loaded = 0;
653var chosen_loading = 0;
654function do_chosen() {
655	if($('.do-chosen').length) {
656		if(!chosen_loaded) {
657			if(!chosen_loading) {
658				chosen_loading = 1;
659				add_css(shared_root+'/js/jquery/jquery.chosen/chosen.min.css');
660				$.when(add_js(shared_root+'/js/jquery/jquery.chosen/chosen.jquery.min.js')).done(function() {
661					chosen_loaded = 1;
662					$('.do-chosen').chosen();
663
664					$('.do-chosen').on('chosen:showing_dropdown', function(event, params) {
665						var chosen_container = $( event.target ).next( '.chosen-container' );
666						var dropdown = chosen_container.find( '.chosen-drop' );
667						var dropdown_top = dropdown.offset().top - $(window).scrollTop();
668						var dropdown_height = dropdown.height();
669						var viewport_height = $(window).height();
670					 
671						if ( dropdown_top + dropdown_height > viewport_height ) {
672						   chosen_container.addClass( 'chosen-drop-up' );
673						}
674					 
675					 });
676					 $('.do-chosen').on('chosen:hiding_dropdown', function(event, params) {
677						$( event.target ).next( '.chosen-container' ).removeClass( 'chosen-drop-up' );
678					 });
679				});
680			}
681		} else {
682			$('.do-chosen').each(function(){
683				$(this).siblings('.chosen-container').css('width', realWidth($(this)));
684				$(this).trigger("chosen:updated");
685			});
686		}
687	}
688}
689function kill_chosen() {
690	$(".do-chosen").chosen("destroy");
691	chosen_loaded = 0;
692	chosen_loading = 0;
693}
694function realWidth($element){
695	var $clone = $element.clone();
696	$clone.css({"display":"block","visibility":"hidden"});
697	$($element).parent('.field-wrap').append($clone);
698	var width = $clone.outerWidth();
699	$clone.remove();
700	return width;
701}
702do_chosen();
703
704
705/* ----------------------------------------------------------------------------------------------------------------------- */
706/* Conditional Field Handling -------------------------------------------------------------------------------------------- */
707/* ----------------------------------------------------------------------------------------------------------------------- */
708if(typeof conditional_field_js_data_arr !== 'undefined') {	
709	$.each(conditional_field_js_data_arr, function(conditional_field_id,conditions) {
710		$.each(conditions, function(key,arr) {
711			if($('.field-wrap[data-field-id="'+arr.conditional_field_id+'"]')) {
712				$('.field-wrap[data-field-id="'+arr.conditional_field_id+'"]').addClass('conditional-field-controller')
713			}
714		});
715	});
716
717	if($('.conditional-field-controller').length) {
718		$('.conditional-field-controller').each(function() {
719			var controller_field_wrap = $(this);
720			var controller_field_type = $(controller_field_wrap).attr('data-field-type');
721			var controller_field_id = $(controller_field_wrap).attr('data-field-id');
722			var controller_html_field_type = controller_field_type;
723			if(controller_html_field_type == 'multiselect') controller_html_field_type = 'select';
724			if(controller_html_field_type == 'yesno') controller_html_field_type = 'select';
725
726			if(controller_html_field_type == 'radio' || controller_html_field_type == 'checkbox') {
727				$(controller_field_wrap).find('input').change(function() {
728					do_conditional_field_handling();
729				});
730
731			} else {	
732				$(controller_field_wrap).find(controller_html_field_type).first().change(function() {
733					do_conditional_field_handling();
734				});
735			}
736		});
737	}
738
739	function check_conditional_status(field_id) {
740		var conditional_field = $('.conditional-field[data-field-id='+field_id+']');
741		var show_this_field = 0;
742
743		if($(conditional_field).length) {
744			if(typeof conditional_field_js_data_arr[field_id] !== 'undefined') {
745				$.each(conditional_field_js_data_arr[field_id], function(key,arr) {
746					var controller_field_wrap = $('.conditional-field-controller[data-field-id="'+arr.conditional_field_id+'"]');
747
748					if($(controller_field_wrap).length) {
749						var controller_field_type = $(controller_field_wrap).attr('data-field-type');	
750						var controller_html_field_type = controller_field_type;		
751						if(controller_field_type == 'yesno') controller_html_field_type = 'select';
752						if(controller_field_type == 'multiselect') controller_html_field_type = 'select';
753						if(controller_field_type == 'checkbox') controller_html_field_type = 'input';
754						if(controller_field_type == 'radio') controller_html_field_type = 'input';
755						var controller_field = $(controller_field_wrap).find(controller_html_field_type).first();
756						
757						if($(controller_field).length) {
758							switch(controller_field_type) {
759								case 'select':
760								case 'yesno':
761									if($(controller_field_wrap).find('select').first().val() == arr.conditional_field_option_id) show_this_field = 1;
762									break;
763
764								case 'radio':
765									if($(controller_field_wrap).find('input:checked').length && $(controller_field_wrap).find('input:checked').val() == arr.conditional_field_option_id) show_this_field = 1;
766									break;
767
768								case 'multiselect':
769									if($(controller_field_wrap).find('select').first().find('option:selected').length) {
770										$(controller_field_wrap).find('select').first().find('option:selected').each(function() {
771											if($(this).val() == arr.conditional_field_option_id) show_this_field = 1;
772										});
773									}
774									break;
775
776								case 'checkbox':
777									if($(controller_field_wrap).find('input:checked').length) {
778										$(controller_field_wrap).find('input:checked').each(function() {
779											if($(this).val() == arr.conditional_field_option_id) show_this_field = 1;
780										});
781									}
782									break;
783								
784							}
785						}
786					}
787				});
788				
789				if(show_this_field) {
790					if($(conditional_field).find('.conditionally-required').length) $(conditional_field).find('.conditionally-required').removeClass('conditionally-required');
791					$(conditional_field).show();
792					$(conditional_field).addClass('show-field-conditionally');
793
794					
795				} else {
796					if($(conditional_field).find('.required')) $(conditional_field).find('.required').addClass('conditionally-required');
797					$(conditional_field).removeClass('show-field-conditionally');
798
799					switch($(conditional_field).attr('data-field-type')) {
800						case 'radio':
801						case 'checkbox':
802							$(conditional_field).hide().find('input').removeAttr('checked');
803							break;
804						
805						case 'select':
806						case 'multiselect':
807						case 'yesno':					
808							$(conditional_field).hide().find('select').first().val('');
809							break;
810
811						case 'textarea':
812							$(conditional_field).hide().find('textarea').first().val('');
813							break;
814						
815						default:
816						case 'text':
817							$(conditional_field).hide().find('input').first().val('');
818							break;
819					}
820				}
821			}
822		}
823
824		return false;
825	}
826
827	function do_conditional_field_handling() {
828		$('.conditional-field').each(function() {
829			var field_id = $(this).attr('data-field-id');
830			check_conditional_status(field_id);
831		});
832
833		// now show/hide entire section if there are no visible fields
834		$('.form-section').each(function() {
835			var section = $(this);
836			if($(section).find('.field-wrap.conditional-field').length && !$(section).find('.field-wrap').not('.conditional-field').length) {
837				var show_section = 0;
838				$(section).find('.conditional-field').each(function() {
839					if($(this).css('display') !== 'none' || $(this).hasClass('show-field-conditionally')) show_section = 1;
840				});
841
842				if(show_section) {
843					$(section).show();
844				} else {
845					$(section).hide();
846				}
847			}
848		});
849
850		$(window).resize();
851		do_chosen();
852		calculate_fees();
853		do_checkboxes();
854	}
855
856	do_conditional_field_handling();
857}
858
859// form validation
860function do_form_validation(fields,require_captcha,do_not_show_errors) {
861	var error = '';
862	var validated_radios_and_checkboxes = new Array();
863	if(!require_form_captcha) require_captcha = 0;
864
865	$('.required').removeClass('error');
866
867	$(fields).each(function() {
868		var field_type = $(this).prop('nodeName').toLowerCase();
869		if(field_type == 'input') {
870			if($(this).attr('type') == 'checkbox') field_type = 'checkbox';
871			if($(this).attr('type') == 'radio') field_type = 'radio';
872		}
873
874		switch(field_type) {
875			case 'input':
876			case 'select':
877			case 'textarea':
878			default:
879				if(!$(this).val()) {
880					$(this).addClass('error');
881					var label = $(this).closest('.field-wrap').find('label').html().replace('<em>*</em>','');
882					error += (error?'<br />':'')+'The Field "'+label+'" is required.';
883				}
884				break;
885
886			case 'checkbox':
887			case 'radio':
888				var field_name = $(this).attr('name');
889
890				var already_validated = 0;
891				for(i=0;i<validated_radios_and_checkboxes.length;i++) {
892					if(validated_radios_and_checkboxes[i] == field_name) already_validated = 1;
893				}
894
895				if(!already_validated) {
896					if(!$('input[name="'+field_name+'"]:checked').length) {
897						$(this).addClass('error');
898						var label = $(this).closest('.field-wrap').find('label').first().html().replace('<em>*</em>','');
899						error += (error?'<br />':'')+'The Field "'+label+'" is required.';
900					}
901
902					validated_radios_and_checkboxes.push(field_name);
903				}
904				break;
905		}
906	});
907
908	// captcha validation
909	if(require_captcha) {
910		if((!is_multi_step_form || (cur_step == step_count)) && $(form).find('.recaptcha_widget').length) {
911			var googleResponse = jQuery('#g-recaptcha-response').val();
912			if (!googleResponse) error += (error?'<br />':'')+'Please check the "I\'m not a robot" box.';
913		}
914	}
915
916	// show error message if present
917	if(error && !do_not_show_errors) showAlert(error,'bad');
918
919	return error;
920}
921
922
923/* ----------------------------------------------------------------------------------------------------------------------- */
924/* Maintain Partial Submissions (via localstorage) ----------------------------------------------------------------------- */
925/* ----------------------------------------------------------------------------------------------------------------------- */
926if($('#main-submission-form').hasClass('maintain-partial-submissions')) {
927	// clear local storage if successful submission cookie is present
928	if($('#main-submission-form').hasClass('clear-existing-partial-submissions')) {
929		localStorage.clear();
930	}
931
932	if($('#global-cookie-notice').length) $('#global-cookie-notice').hide();
933
934	$.when(add_js(shared_root+'/js/jquery/jquery.cookie/jquery.cookie.js')).done(function() {
935		// gdpr cookie acceptance
936		if($('#global-cookie-notice').length) {
937			$('#global-cookie-notice').slideDown('slow');
938
939			$('#global-cookie-notice-button').click(function() {
940				var id = $(this).attr('data-attr-id');
941				$('#global-cookie-notice').fadeOut('fast',function() {
942					$(this).remove();
943				});
944				$.cookie('cookie-consent-'+id,1,{expires: 60, path: '/'});
945				return false;
946			});
947		}
948	});
949
950	var form = $('#main-submission-form');
951	var key_prefix = 'f'+$(form).attr('data-fid')+'-';
952	var soft_save_t;
953
954	setTimeout(function() {
955		$('input[type=text], textarea').keyup(function() { do_soft_save(); });
956		$('input[type=radio], textarea').change(function() { do_soft_save(); });
957		$('input[type=checkbox]').change(function() { do_soft_save(); });
958		$('select').change(function() { do_soft_save(); });
959	}, 1000);
960
961	function do_soft_save() {
962		clearTimeout(soft_save_t);
963		soft_save_t = setTimeout(function() {
964			var postData = {};
965			var form_data = $(form).serializeArray();
966			for (var i = 0; i < form_data.length; i++) {
967				if(form_data[i]['name'].indexOf('form_submitted_') >= 0) continue;
968
969				if (form_data[i]['name'].endsWith('[]')) {
970					var name = form_data[i]['name'];
971					// name = name.substring(0, name.length - 2);
972					if (!(name in postData)) {
973						postData[name] = [];
974					}
975					postData[name].push(form_data[i]['value']);
976
977				} else {
978					postData[form_data[i]['name']] = form_data[i]['value'];
979				}
980			}
981
982			$.each(postData,function(key,val) {
983				if(val && val != '') {
984					if(Array.isArray(val)) {
985						val = JSON.stringify(val);
986					}
987					localStorage.setItem(key_prefix+key,val);
988				}
989			});
990		},1000);
991	}
992
993	var has_partial_submission_data = 0;
994	for (var key in localStorage) {
995		var value = localStorage.getItem(key);
996		var key = key.replace(key_prefix,'');
997
998		if(value != '' && value != '-1') {
999			if($('input[name="'+key+'"]').length) {
1000				var field = $('input[name="'+key+'"]');
1001				var type = $(field).attr('type');
1002
1003				if(type == 'checkbox') {
1004					try {
1005						tmp_val = JSON.parse(value);
1006						value = tmp_val;
1007					} catch(e) {
1008					}
1009	
1010					$(field).each(function() {
1011						if((typeof value !== 'string' && inArray($(this).val(),value)) || ($(this).val() == value)) {
1012							$(this).prop('checked','checked').change();
1013							if(key.indexOf('use_google_smart_search') == -1) has_partial_submission_data = 1;
1014						} else {
1015							$(this).prop('checked',false).change();
1016						}
1017					});
1018
1019				} else if (type == 'radio') {
1020					$(field).each(function() {
1021						if($(this).val() == value) {
1022							$(this).prop('checked','checked').change();
1023						} else {
1024							$(this).prop('checked',false).change();
1025						}
1026					});
1027
1028				} else {
1029					$(field).val(value);					
1030					has_partial_submission_data = 1;
1031				}
1032
1033			} else if($('select[name="'+key+'"]').length) {
1034				var field = $('select[name="'+key+'"]');
1035				if($(field).attr('multiple')) {
1036					field.find('option').each(function() {
1037						if (value.indexOf($(this).val()) !== -1) {
1038							$(this).prop('selected', true);
1039						}
1040					});
1041				} else {
1042					$(field).val(value);
1043				}
1044				has_partial_submission_data = 1;
1045
1046				// reinit multi-selects
1047				if(chosen_loaded) kill_chosen();
1048				do_chosen();
1049				$(field).change();
1050
1051				
1052			} else if($('textarea[name="'+key+'"]').length) {
1053				var field = $('textarea[name="'+key+'"]');
1054				$(field).val(value);
1055				has_partial_submission_data = 1;
1056			}
1057		}
1058	}
1059
1060	if(has_partial_submission_data) $('#partial-submissions-notification').show();
1061	$('#reset-partial-submission-data-button').click(function() {
1062		localStorage.clear();
1063		var url = window.location.href;
1064		window.location.href = url+(url.indexOf('?') >= 0?'&':'?')+'reset=1';
1065		return false;
1066	});
1067}
1068
1069function inArray(needle, haystack) {
1070    var length = haystack.length;
1071    for(var i = 0; i < length; i++) {
1072        if(haystack[i] == needle) return true;
1073    }
1074    return false;
1075}
1076
1077
1078/* ----------------------------------------------------------------------------------------------------------------------- */
1079/* Multi Step Handling --------------------------------------------------------------------------------------------------- */
1080/* ----------------------------------------------------------------------------------------------------------------------- */
1081if(is_multi_step_form) {
1082	// first move captcha
1083	if($('#form-section-captcha').length) {
1084		var target_section = $('#form-section-captcha').prev('.form-section');
1085		$('#form-section-captcha').contents().appendTo($(target_section));
1086		$('#form-section-captcha').remove();
1087	}
1088
1089	// now move send myself a copy field
1090	if($('#send-myself-a-copy-field-wrap').length) {
1091		var target_section = $('#send-myself-a-copy-field-wrap').prev('.form-section');
1092		$('#send-myself-a-copy-field-wrap').appendTo($(target_section));
1093	}
1094
1095	var step_count = $(form).find('.form-section').length;
1096
1097	// only initiate if we have more than one section
1098	if(step_count > 1) {
1099		// define submit button and add prev/next buttons
1100		$(submit_button).before('<a href="#" id="multi-step-form-prev" class="button">Back</a>&nbsp;');
1101		$(submit_button).before('<a href="#" id="multi-step-form-next" class="button">Next</a>&nbsp;');
1102
1103		// do step initiation function
1104		do_form_step(1);
1105
1106		// add click handling for prev/next step button
1107		$('#multi-step-form-prev').click(function() {
1108			cur_step = cur_step - 1;
1109			cur_idx = cur_step-1;
1110			do_form_step();
1111			return false;
1112		});
1113		$('#multi-step-form-next').click(function() {
1114			var has_error = do_step_validation();
1115
1116			if(!has_error) {
1117				cur_step = cur_step + 1;
1118				cur_idx = cur_step-1;
1119				do_form_step();
1120			}
1121
1122			return false;
1123		});
1124
1125		// add keydown/enter handling override
1126		$('input').keydown(function(e) {
1127			if(e.keyCode==13) {
1128				var has_error = do_step_validation();
1129
1130				if(!has_error) {
1131					$('#multi-step-form-next').click();
1132				}
1133
1134				return false;
1135			}
1136		});
1137
1138		// add last step validation (on form submit)
1139		$(form).submit(function() {
1140			if(!$(this).hasClass('paypal-business-submittable')) {
1141				var has_error = do_step_validation();
1142				if(has_error) return false;
1143			}
1144		});
1145	}
1146
1147	// main function to init each step
1148	function do_form_step(is_init=false) {
1149		// hide all sections but current
1150		$(form).find('.form-section').hide();
1151		$(form).find('.form-section').eq(cur_idx).show();
1152
1153		// add counter to top of form, step cur step
1154		if(!$('#form-step-counter').length) $(form).prepend('<h3 class="form-step-counter" id="form-step-counter">Step <span id="form-step-counter-current">'+cur_step+'</span>
1154 of '+step_count+'</h3>');
1155		$('#form-step-counter-current').html(cur_step);
1156
1157		show_or_hide_multi_step_submit_button();
1158
1159		// scroll back to top of form
1160		if(!is_init) {
1161			var scroll_to_top_amount = $(form).offset().top - 50;;
1162			if($('#header').length) {
1163				if($('#header').css('position') == 'fixed') scroll_to_top_amount -= $('#header').height();
1164			} else if($('.header').length) {
1165				if($('.header').css('position') == 'fixed') scroll_to_top_amount -= $('.header').height();
1166			}
1167			$('html,body').animate({'scrollTop':scroll_to_top_amount+'px'},'fast');
1168		}
1169
1170		// fire window resize to reinit signature pad if present
1171		$(window).resize();
1172
1173		// do payment method select handling
1174		if($("#payment-method").length) $("#payment-method").change();
1175
1176		// reinit multi-selects
1177		if(chosen_loaded) kill_chosen();
1178		do_chosen();
1179	}
1180
1181	function do_step_validation() {
1182		return do_form_validation($(form).find('.form-section').eq(cur_idx).find('.required').not('.conditionally-required'),1);
1183	}
1184}
1185
1186function show_or_hide_multi_step_submit_button() {
1187	// show/hide prev/next buttons based on current step
1188	if(cur_step == 1) {
1189		$('#multi-step-form-prev').hide();
1190		$('#multi-step-form-next').show();
1191		$(submit_button).hide();
1192
1193	} else if(cur_step == step_count) {
1194		$('#multi-step-form-prev').show();
1195		$('#multi-step-form-next').hide();
1196
1197		// reinit recaptcha if present
1198		if($('.cf-turnstile').length) {
1199			if (window.turnstile && typeof turnstile.reset === 'function') {
1200				// reset the first widget on the page
1201				turnstile.reset(0); // 0 is the first widget
1202			}
1203		}
1204
1205		$(submit_button).show();
1206
1207	} else {
1208		$('#multi-step-form-prev').show();
1209		$('#multi-step-form-next').show();
1210		$(submit_button).hide();
1211	}		
1212}
1213
1214
1215/* ----------------------------------------------------------------------------------------------------------------------- */
1216/* JS Client Side Validation --------------------------------------------------------------------------------------------- */
1217/* ----------------------------------------------------------------------------------------------------------------------- */
1218if(!is_multi_step_form && $(form).find('input[type=file]').length) {
1219	$(form).submit(function() {
1220		var has_error = do_form_validation($(form).find('.required').not('.conditionally-required'),1);
1221		if(has_error) return false;
1222	});
1223}
1224
1225
1226/* ----------------------------------------------------------------------------------------------------------------------- */
1227/* Price Adjustment Field Handling --------------------------------------------------------------------------------------- */
1228/* ----------------------------------------------------------------------------------------------------------------------- */
1229if($('.price-adjustment-field').length && $('#amount').length && (typeof field_option_prices_arr !== "undefined" || $('.usd-field.price-adjustment-field').length)) {
1230	$('.price-adjustment-field').change(function() {
1231		calculate_fees();
1232	});
1233	$('.usd-field.price-adjustment-field').keyup(function() {
1234		calculate_fees();
1235	});
1236	$('.usd-field.price-adjustment-field').keydown(function() {
1237		calculate_fees();
1238	});
1239}
1240
1241
1242/* ----------------------------------------------------------------------------------------------------------------------- */
1243/* Customer Paying Fee Handling ------------------------------------------------------------------------------------------ */
1244/* ----------------------------------------------------------------------------------------------------------------------- */
1245if($('#will_pay_fees').length) {
1246	$('#will_pay_fees').change(function() {
1247		calculate_fees();
1248	});
1249	calculate_fees();
1250}
1251
1252$('#simple_payment_amount-field').keyup(function() {
1253	calculate_fees();
1254});
1255
1256
1257function get_payment_amount() {
1258	if($('#simple_payment_amount-field').length) {
1259		var amount = parseFloat($('#simple_payment_amount-field').val().replace(',','').replace('$',''));
1260	
1261	} else {
1262		var amount = parseFloat($('#amount').attr('data-base-amount'));
1263		if(isNaN(amount)) amount = 0;
1264
1265		if($('.price-adjustment-field').length && $('#amount').length && (typeof field_option_prices_arr !== "undefined" || $('.usd-field.price-adjustment-field').length)) {
1266			$('.price-adjustment-field').each(function() {
1267				if(!$(this).closest('.field-wrap').hasClass('conditional-field') || ($(this).closest('.field-wrap').hasClass('conditional-field') && $(this).closest('.field-wrap').css('display') != 'none')) {
1268					var field_name = $(this).attr('name').replace('[]','');
1269
1270					var type = $(this)[0].nodeName.toLowerCase();
1271					switch(type) {
1272						case 'select':
1273							if($(this).attr('multiple')) {
1274								var val = $(this).val();
1275								if(val) {
1276									for(i=0;i<val.length;i++) {
1277										if(typeof field_option_prices_arr[field_name] !== "undefined" && typeof field_option_prices_arr[field_name][val[i]] !== "undefined") {
1278											amount += parseFloat(field_option_prices_arr[field_name][val[i]].toString().replace(',',''));
1279										}
1280									}
1281								}
1282							} else {
1283								var val = $(this).val();
1284								if(val) {
1285									if(typeof field_option_prices_arr[field_name] !== "undefined" && typeof field_option_prices_arr[field_name][val] !== "undefined") {
1286										amount += parseFloat(field_option_prices_arr[field_name][val].toString().replace(',',''));
1287									}
1288								}
1289							}
1290							break;
1291
1292						case 'input':
1293							if($(this).attr('type') == 'checkbox' || $(this).attr('type') == 'radio') {
1294								if($(this).is(':checked')) {
1295									var val = $(this).val();
1296									if(val) {
1297										if(typeof field_option_prices_arr[field_name] !== "undefined" && typeof field_option_prices_arr[field_name][val] !== "undefined") {
1298											amount += parseFloat(field_option_prices_arr[field_name][val].toString().replace(',',''));
1299										}
1300									}
1301								}
1302							}
1303
1304							if($(this).hasClass('usd-field')) {
1305								var val = parseFloat($(this).val().replace(',',''));
1306								if(val > 0) amount += parseFloat(val);
1307							}
1308							break;
1309					}
1310				}
1311			});
1312		}
1313
1314		// discount code
1315		if(amount > 0 && discount_type && discount_amount > 0) {
1316			var discount = 0;
1317			if(discount_type == 'percentage') {
1318				discount = amount * (discount_amount/100);
1319			} else {
1320				discount = discount_amount;
1321			}
1322			amount -= discount;
1323		}
1324
1325		if(amount <= 0) amount = 0;
1326
1327		$('#amount').html('$'+amount.toLocaleString('us', {minimumFractionDigits: 2, maximumFractionDigits: 2}));
1328
1329		var amount = parseFloat($('#amount').text().replace(',','').replace('$',''));
1330	}
1331	if(isNaN(amount)) amount = 0;
1332	return amount;	
1333}
1334
1335if(typeof stripe !== 'undefined' && stripe !== null) {
1336	// one time stripe payment, allows for card, google pay or apple pay if the client has them enabled
1337	if(stripe_payment_frequency == 0 && enable_google_and_apple_pay == 1) {
1338		let elements;
1339		let stripePaymentElementOptions;
1340		let stripePaymentElement;
1341	
1342		function updateStripePaymentElement() {
1343			if (typeof stripePaymentElement !== 'undefined') {
1344				stripePaymentElement.unmount(); // Use unmount() to remove the existing instance
1345			}
1346	
1347			amount = get_payment_amount();
1348	
1349			if(amount > 0) {
1350				const options = {
1351					mode: 'payment',
1352					amount: amount*100, // in cents for stripe
1353					currency: 'usd',
1354					paymentMethodCreation: 'manual',
1355					paymentMethodTypes: ['card'],
1356					appearance: {
1357						theme: 'flat'
1358					},
1359				};
1360		
1361				// Set up Stripe.js and Elements to use in checkout form
1362				elements = stripe.elements(options);
1363		
1364				// Create and mount the Payment Element
1365				stripePaymentElementOptions = { layout: 'tabs' };
1366				stripePaymentElement = elements.create('payment', stripePaymentElementOptions);
1367				stripePaymentElement.mount('#stripe-payment-element');
1368			}
1369		}
1370	
1371		updateStripePaymentElement();
1372		
1373		document.getElementById('main-submission-form').addEventListener('submit', async (event) => {
1374			if($('#payment-method').length && $('#payment-method').val() != 'stripe') {
1375
1376			} else {
1377				amount = get_payment_amount();
1378				if(amount > 0) {
1379					event.preventDefault();
1380			
1381					document.getElementById('submit-button').disabled = true; // Disable the button to prevent duplicate submissions
1382			
1383					const {error: submitError} = await elements.submit();
1384					if (submitError) {
1385						console.log(submitError);
1386						document.getElementById('stripe-error-message').textContent = submitError.message;
1387						document.getElementById('submit-button').disabled = false; // Re-enable the button
1388						return;
1389					}
1390			
1391					const {error, confirmationToken} = await stripe.createConfirmationToken({
1392						elements,
1393						params: {
1394							return_url: window.location.href,
1395						}
1396					});
1397			
1398					if (error) {
1399						document.getElementById('stripe-error-message').textContent = error.message;
1400						document.getElementById('submit-button').disabled = false; // Re-enable the button
1401						return;
1402					}
1403			
1404					if(confirmationToken && confirmationToken.id) {
1405						// Add the paymentIntent ID to the form
1406						const hiddenInput = document.createElement('input');
1407						hiddenInput.type = 'hidden';
1408						hiddenInput.name = 'stripeConfirmationToken';
1409						hiddenInput.value = confirmationToken.id;
1410						document.getElementById('main-submission-form').appendChild(hiddenInput);
1411			
1412						// Submit the form to the server
1413						document.getElementById('submit-button').disabled = false;
1414						document.getElementById('main-submission-form').submit();            
1415					} else {
1416						document.getElementById('stripe-error-message').textContent = 'Unable to retrieve confirmation token. Please try again.';
1417						document.getElementById('submit-button').disabled = false; // Re-enable the button
1418						return false;   
1419					}
1420				}
1421			}
1422		});
1423	
1424	// recurring or user selectable frequency, credit card only
1425	} else {
1426		// Create an instance of Elements.
1427		var elements = stripe.elements();
1428
1429		// Custom styling can be passed to options when creating an Element.
1430		// (Note that this demo uses a wider set of styles than the guide below.)
1431		var style = {
1432			base: {
1433				color: "#32325d",
1434				lineHeight: "18px",
1435				fontFamily: "'Helvetica Neue', Helvetica, sans-serif",
1436				fontSmoothing: "antialiased",
1437				fontSize: "16px",
1438				"::placeholder": {
1439				color: "#aab7c4"
1440				}
1441			},
1442			invalid: {
1443				color: "#fa755a",
1444				iconColor: "#fa755a"
1445			}
1446		};
1447
1448		// Create an instance of the card Element.
1449		var card = elements.create("card", {style: style});
1450
1451		// Add an instance of the card Element into the `card-element` <div>.
1452		card.mount("#card-element");
1453
1454		// Handle real-time validation errors from the card Element.
1455		card.addEventListener("change", function(event) {
1456			var displayError = document.getElementById("card-errors");
1457			if (event.error) {
1458				displayError.textContent = event.error.message;
1459			} else {
1460				displayError.textContent = "";
1461			}
1462		});
1463
1464		// Handle form submission.
1465		var form = document.getElementById("main-submission-form");
1466		form.addEventListener("submit", function(event) {
1467			var amount = get_payment_amount();
1468
1469			if(amount > 0) {
1470				if($("#payment-method").val() == "stripe") {
1471					if(stripe_payment_frequency != 0) {
1472						if($('.payment-frequency-selection-radio:checked').length && $('.payment-frequency-selection-radio:checked').val() == 1) {
1473							if(confirm("Are you sure you want to submit this form and setup an automatically recurring "+$('#recurring_payment_interval').val()+" payment?")) {
1474								$("body").append('<div id="form-loading"></div>');
1475							} else {
1476								event.stopPropagation();
1477								event.preventDefault();
1478								return false;
1479							}
1480
1481						} else {
1482							if($("#per-month").length) {
1483								if(confirm("Are you sure you want to submit this form and setup an automatically recurring monthly payment?")) {
1484									$("body").append('<div id="form-loading"></div>');
1485								} else {
1486									event.stopPropagation();
1487									event.preventDefault();
1488									return false;
1489								}
1490							} else {
1491								$("body").append('<div id="form-loading"></div>');
1492							}
1493						}
1494					}
1495					
1496					event.preventDefault();
1497
1498					var card_name = document.getElementById("card-name").value;
1499					stripe.createToken(card, {name: card_name}).then(function(result) {
1500						if (result.error) {
1501							// Inform the user if there was an error.
1502							var errorElement = document.getElementById("card-errors");
1503							errorElement.textContent = result.error.message;
1504							$("#form-loading").remove();
1505						} else {
1506							// Send the token to your server.
1507							stripeTokenHandler(result.token);
1508						}
1509					});
1510				}
1511			}
1512		});
1513
1514		// Send Stripe Token to Server
1515		function stripeTokenHandler(token) {
1516			var form = $('#main-submission-form');
1517
1518			// Insert the token ID into the form so it gets submitted to the server
1519			// Add Stripe Token to hidden input
1520			var hiddenInput = document.createElement("input");
1521			hiddenInput.setAttribute("type", "hidden");
1522			hiddenInput.setAttribute("name", "stripeToken");
1523			hiddenInput.setAttribute("value", token.id);
1524			$(form).append(hiddenInput);
1525			// Submit form
1526			$(form).submit();
1527		}
1528	}
1529}
1530
1531function calculate_fees() {
1532	var amount = get_payment_amount();
1533
1534	if($('#will_pay_fees').length) {
1535		if(
1536			(
1537				$('select[name=payment_method]').val() == 'authdotnet' || 
1538				$('select[name=payment_method]').val() == 'bluesnap' || 
1539				$('select[name=payment_method]').val() == 'clover' || 
1540				$('select[name=payment_method]').val() == 'stripe' 
1541			) && 
1542			$('#will_pay_fees').prop('checked') && 
1543			!isNaN(amount) && amount > 0
1544		) {
1545			var desired_net = amount;
1546			var base_fee_percent = 2.9; // stripe percentage fee
1547			var flat_fee = 0.30; // stripe flat fee amount
1548
1549			if($('select[name=payment_method]').val() == 'authdotnet') {
1550				base_fee_percent = 2.9; // auth.net percentage fee
1551			}
1552			if($('select[name=payment_method]').val() == 'clover') {
1553				base_fee_percent = 3.5; // clover percentage fee
1554				flat_fee = 0.10;
1555			}
1556
1557			var amount_to_charge = (desired_net + flat_fee) / (1 - (base_fee_percent/100));
1558			var calculated_fee = amount_to_charge - desired_net;
1559			$('#subtotal').text(number_format(amount,2));
1560			$('#fee').text(number_format(calculated_fee,2));
1561			$('#grand-total').text(number_format(amount_to_charge,2));
1562			$('#field-wrap-fee-calculation-area').show();
1563		} else {
1564			$('#field-wrap-fee-calculation-area').hide();
1565		}
1566	}
1567
1568	if(amount <= 0) {
1569		var hide_payment_methods = 1;
1570		if($('.field-wrap-simple-payment-field > label').length && $('.field-wrap-simple-payment-field > label').text().indexOf('*') >= 0) hide_payment_methods = 0;
1571		if(hide_payment_methods) $('#payment-method-field-wrap, #non-card-method-field-wrap, #stripe-fields, #authdotnet-cc-fields, #authdotnet-ach-fields, #bluesnap-cc-fields, #clover-cc-fields').hide();
1572		$(submit_button).val("Submit");
1573		$("#form-section-captcha").show();
1574
1575	} else {
1576		if($('select[name=payment_method]').find('option').length > 1) $('#payment-method-field-wrap').show();		
1577		$("#payment-method").change();		
1578	}
1579
1580	if (typeof stripe_payment_frequency !== 'undefined' && stripe_payment_frequency == 0 && typeof updateStripePaymentElement === 'function') {
1581        updateStripePaymentElement();
1582    }
1583}
1584
1585calculate_fees();
1586
1587
1588function number_format (number, decimals, dec_point, thousands_sep) {
1589    // Strip all characters but numerical ones.
1590    number = (number + '').replace(/[^0-9+\-Ee.]/g, '');
1591    var n = !isFinite(+number) ? 0 : +number,
1592        prec = !isFinite(+decimals) ? 0 : Math.abs(decimals),
1593        sep = (typeof thousands_sep === 'undefined') ? ',' : thousands_sep,
1594        dec = (typeof dec_point === 'undefined') ? '.' : dec_point,
1595        s = '',
1596        toFixedFix = function (n, prec) {
1597            var k = Math.pow(10, prec);
1598            return '' + Math.round(n * k) / k;
1599        };
1600    // Fix for IE parseFloat(0.55).toFixed(0) = 0;
1601    s = (prec ? toFixedFix(n, prec) : '' + Math.round(n)).split('.');
1602    if (s[0].length > 3) {
1603        s[0] = s[0].replace(/\B(?=(?:\d{3})+(?!\d))/g, sep);
1604    }
1605    if ((s[1] || '').length < prec) {
1606        s[1] = s[1] || '';
1607        s[1] += new Array(prec - s[1].length + 1).join('0');
1608    }
1609    return s.join(dec);
1610}
1611
1612
1613/* ----------------------------------------------------------------------------------------------------------------------- */
1614/* PayPal for Business / Venmo Button Display Handling and Post Processing ----------------------------------------------- */
1615/* ----------------------------------------------------------------------------------------------------------------------- */
1616// documentation https://developer.paypal.com/docs/checkout/standard/integrate/ && https://developer.paypal.com/docs/checkout/pay-with-venmo/integrate/
1617function do_paypal_business_handling() {
1618    var purchase_units = [];
1619    purchase_units[0] = {};
1620    purchase_units[0].amount = {};
1621	purchase_units[0].description = document.title;
1622	purchase_units[0].amount.value = get_payment_amount();
1623
1624	$('input').keydown(function(e) {
1625		if($('#payment-method').val() == 'paypal_business') {
1626			if(e.keyCode == 13) {
1627				do_form_validation($(form).find('.required').not('.conditionally-required'),0);
1628				return false;
1629			}
1630		}
1631	});
1632
1633	paypal.Buttons({
1634		style: {
1635			color: 'gold',
1636			shape: 'rect',
1637			label: 'paypal',
1638			layout: 'vertical',	  
1639		},
1640
1641		onInit: function (data, actions) {
1642			//actions.disable();
1643
1644			// loop through fields an
1645			var form_has_error = do_form_validation($(form).find('.required').not('.conditionally-required'),0,1);
1646			if(form_has_error) {
1647				//actions.disable();
1648			} else {
1649				//actions.enable();
1650			}
1651		},
1652
1653		onClick: function (data) {
1654			$('#paypal_funding_source').val(data.fundingSource);
1655			purchase_units[0].amount.value = get_payment_amount();
1656			var form_has_error = do_form_validation($(form).find('.required').not('.conditionally-required'),0);
1657			if(form_has_error) {
1658				return false;
1659			}
1660		},
1661
1662		createOrder: function (data, actions) {
1663			purchase_units[0].amount.value = get_payment_amount();
1664
1665			return actions.order.create({
1666				purchase_units: purchase_units,
1667			});
1668		},
1669
1670		onApprove: function (data, actions) {
1671			return actions.order.capture().then(function (orderData) {
1672				// Full available details
1673				// console.log('Capture result', orderData, JSON.stringify(orderData, null, 2));
1674
1675				// Show a success message within this page, e.g.
1676				const element = document.getElementById('paypal-button-container');
1677				element.innerHTML = '';
1678				element.innerHTML = '<h3>Thank you for your payment!</h3>';
1679
1680				// Or go to another URL:  actions.redirect('thank_you.html');
1681				document.getElementById('paypal_json').value = JSON.stringify(orderData, null, 2);
1682				$('#main-submission-form').addClass('paypal-business-submittable').submit();         
1683			});
1684		},
1685
1686		onCancel: function(data, actions) {
1687		},
1688
1689		onError: function (err) {
1690			// console.log(err);
1691		}
1692	}).render('#paypal-button-container');
1693}

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.