1(function(){ 2 function getHeaderOffset(){ 3 var header = document.querySelector('.elementor-location-header'); 4 if (!header) return 0; 5 var height = header.offsetHeight || 0; 6 var extra = 16; // small breathing space below header 7 return height + extra; 8 } 9 var stripeInstance = null; 10 11 function ensureStripe(){ 12 if (!stripeInstance && window.Stripe && window.HogbackGV && HogbackGV.publishableKey) { 13 stripeInstance = Stripe(HogbackGV.publishableKey); 14 } 15 return stripeInstance; 16 } 17 18 function selectFlight(element) { 19 document.querySelectorAll('.flight-option').forEach(function(opt){ opt.classList.remove('selected'); }); 20 element.classList.add('selected'); 21 calculateTotal(); 22 // Smooth scroll to Number of Guests with header-based offset 23 var guestsEl = document.getElementById('guests'); 24 if (guestsEl) { 25 var rect = guestsEl.getBoundingClientRect(); 26 var scrollTop = window.pageYOffset || document.documentElement.scrollTop; 27 var offset = getHeaderOffset(); 28 var targetY = rect.top + scrollTop - offset; 29 window.scrollTo({ top: targetY, behavior: 'smooth' }); 30 // Also focus for accessibility after scroll 31 setTimeout(function(){ guestsEl.focus(); }, 300); 32 } 33 } 34 35 function getSelectedFlight(){ 36 var checked = document.querySelector('input[name="flight"]:checked'); 37 if (!checked) return { price: 0, name: '' }; 38 var label = checked.closest('.flight-option'); 39 var name = label ? (label.querySelector('h3') ? label.querySelector('h3').textContent.trim() : '') : ''; 40 var price = parseFloat(checked.value || '0'); 41 return { price: price, name: name }; 42 } 43 44 function calculateTotal() { 45 var flight = getSelectedFlight(); 46 var guestsEl = document.getElementById('guests'); 47 var guests = parseInt(guestsEl ? guestsEl.value : '1', 10) || 1; 48 var subtotal = (flight.price || 0) * guests; 49 var serviceFee = 0; 50 var total = subtotal + serviceFee; 51 var fmt = function(n){ return '$' + (n||0).toFixed(2); }; 52 var subtotalEl = document.getElementById('subtotal'); 53 var serviceFeeEl = document.getElementById('serviceFee'); 54 var totalEl = document.getElementById('total'); 55 if (subtotalEl) subtotalEl.innerText = fmt(subtotal); 56 if (serviceFeeEl) serviceFeeEl.innerText = fmt(serviceFee); 57 if (totalEl) totalEl.innerText = fmt(total); 58 } 59 60 function getSelectedGiftcardItems(){ 61 var items = []; 62 document.querySelectorAll('input[name="gift_amount"]:checked').forEach(function(input){ 63 var amount = parseFloat(input.value || '0'); 64 if (amount > 0) { 65 items.push({ amount: amount }); 66 } 67 }); 68 return items; 69 } 70 71 function calculateGiftcardTotal(){ 72 var items = getSelectedGiftcardItems(); 73 var total = items.reduce(function(sum, item){ return sum + (item.amount || 0); }, 0); 74 var totalEl = document.getElementById('giftcardTotal'); 75 if (totalEl) totalEl.innerText = '$' + total.toFixed(2); 76 } 77 78 function bindEvents(){ 79 document.querySelectorAll('.flight-option').forEach(function(label){ 80 var radio = label.querySelector('input[type="radio"]'); 81 if (!radio) return; 82 label.addEventListener('click', function(){ 83 if (radio) { radio.checked = true; } 84 selectFlight(label); 85 }); 86 }); 87 var guests = document.getElementById('guests'); 88 if (guests) guests.addEventListener('change', calculateTotal); 89 calculateTotal(); 90 91 var form = document.getElementById('voucherForm'); 92 if (form) { 93 form.addEventListener('submit', function(e){ 94 e.preventDefault(); 95 var submitBtn = form.querySelector('.btn-submit'); 96 var originalText = submitBtn ? submitBtn.textContent : ''; 97 if (submitBtn) { 98 submitBtn.textContent = 'Processing...'; 99 submitBtn.disabled = true; 100 } 101 var stripe = ensureStripe(); 102 if (!stripe) { 103 alert('Stripe is not initialized. Please set the publishable key.'); 104 if (submitBtn) { 105 submitBtn.textContent = originalText || 'Pay Now'; 106 submitBtn.disabled = false; 107 } 108 return; 109 } 110 111 // Basic client-side validation 112 var email = form.querySelector('#email'); 113 var sender = form.querySelector('#senderName'); 114 var recipient = form.querySelector('#recipientName'); 115 var flight = getSelectedFlight(); 116 var age = form.querySelector('#ageConfirm'); 117 var guestsEl = document.getElementById('guests'); 118 var guests = parseInt(guestsEl ? guestsEl.value : '1', 10) || 1; 119 if (!email.value || !sender.value || !recipient.value || !flight.price || !age.checked) { 120 alert('Please complete all required fields and confirm age.'); 121 if (submitBtn) { 122 submitBtn.textContent = originalText || 'Pay Now'; 123 submitBtn.disabled = false; 124 } 125 return; 126 } 127 128 var data = new FormData(); 129 data.append('action', 'hogback_create_checkout_session'); 130 data.append('nonce', (window.HogbackGV && HogbackGV.nonce) ? HogbackGV.nonce : ''); 131 data.append('email', email.value); 132 data.append('senderName', sender.value); 133 data.append('recipientName', recipient.value); 134 data.append('message', (form.querySelector('#message') || { value: '' }).value); 135 data.append('guests', String(guests)); 136 data.append('flight', String(flight.price)); 137 data.append('flightName', flight.name || 'Tasting Flight'); 138 139 fetch(HogbackGV.ajaxUrl, { method: 'POST', body: data }) 140 .then(function(resp){ return resp.json(); }) 141 .then(function(json){ 142 if (json && json.success && json.data) { 143 // Prefer URL redirect if provided 144 if (json.data.checkoutUrl) { 145 window.location.href = json.data.checkoutUrl; 146 return; 147 } 148 if (json.data.sessionId) {
149 stripe.redirectToCheckout({ sessionId: json.data.sessionId }); 150 return; 151 } 152 } 153 var msg = (json && json.data && json.data.message) ? json.data.message : 'Failed to start checkout.'; 154 alert(msg); 155 if (submitBtn) { 156 submitBtn.textContent = originalText || 'Pay Now'; 157 submitBtn.disabled = false; 158 } 159 }) 160 .catch(function(){ 161 alert('Network error.'); 162 if (submitBtn) { 163 submitBtn.textContent = originalText || 'Pay Now'; 164 submitBtn.disabled = false; 165 } 166 }); 167 }); 168 } 169 170 var giftForm = document.getElementById('giftCardForm'); 171 if (giftForm) { 172 giftForm.querySelectorAll('input[name="gift_amount"]').forEach(function(input){ 173 input.addEventListener('change', function(){ 174 var label = input.closest('.giftcard-option'); 175 if (label) { 176 if (input.checked) { 177 label.classList.add('selected'); 178 } else { 179 label.classList.remove('selected'); 180 } 181 } 182 calculateGiftcardTotal(); 183 }); 184 }); 185 calculateGiftcardTotal(); 186 187 giftForm.addEventListener('submit', function(e){ 188 e.preventDefault(); 189 var submitBtn = giftForm.querySelector('.btn-submit'); 190 var originalText = submitBtn ? submitBtn.textContent : ''; 191 if (submitBtn) { 192 submitBtn.textContent = 'Processing...'; 193 submitBtn.disabled = true; 194 } 195 var stripe = ensureStripe(); 196 if (!stripe) { 197 alert('Stripe is not initialized. Please set the publishable key.'); 198 if (submitBtn) { 199 submitBtn.textContent = originalText || 'Pay Now'; 200 submitBtn.disabled = false; 201 } 202 return; 203 } 204 205 var email = giftForm.querySelector('#gcEmail'); 206 var sender = giftForm.querySelector('#gcSenderName'); 207 var recipient = giftForm.querySelector('#gcRecipientName'); 208 var age = giftForm.querySelector('#gcAgeConfirm'); 209 var items = getSelectedGiftcardItems(); 210 if (!email.value || !sender.value || !recipient.value || items.length === 0 || !age.checked) { 211 alert('Please complete all required fields and select at least one amount.'); 212 if (submitBtn) { 213 submitBtn.textContent = originalText || 'Pay Now'; 214 submitBtn.disabled = false; 215 } 216 return; 217 } 218 219 var data = new FormData(); 220 data.append('action', 'hogback_create_giftcard_checkout_session'); 221 data.append('nonce', (window.HogbackGV && HogbackGV.nonce) ? HogbackGV.nonce : ''); 222 data.append('email', email.value); 223 data.append('senderName', sender.value); 224 data.append('recipientName', recipient.value); 225 data.append('message', (giftForm.querySelector('#gcMessage') || { value: '' }).value); 226 data.append('items', JSON.stringify(items)); 227 data.append('ageConfirm', age.checked ? '1' : ''); 228 229 fetch(HogbackGV.ajaxUrl, { method: 'POST', body: data }) 230 .then(function(resp){ return resp.json(); }) 231 .then(function(json){ 232 if (json && json.success && json.data) { 233 if (json.data.checkoutUrl) { 234 window.location.href = json.data.checkoutUrl; 235 return; 236 } 237 if (json.data.sessionId) {
238 stripe.redirectToCheckout({ sessionId: json.data.sessionId }); 239 return; 240 } 241 } 242 var msg = (json && json.data && json.data.message) ? json.data.message : 'Failed to start checkout.'; 243 alert(msg); 244 if (submitBtn) { 245 submitBtn.textContent = originalText || 'Pay Now'; 246 submitBtn.disabled = false; 247 } 248 }) 249 .catch(function(){ 250 alert('Network error.'); 251 if (submitBtn) { 252 submitBtn.textContent = originalText || 'Pay Now'; 253 submitBtn.disabled = false; 254 } 255 }); 256 }); 257 } 258 } 259 260 document.addEventListener('DOMContentLoaded', bindEvents); 261})();
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.