https://tirtaayuspa.com.ng/vi/wp-content/themes/tirta-ayu-vi-theme/assets/js/theme.js?ver=1790541552
1/** 2 * Tirta Ayu Spa Hardcoded â supplementary theme JS. 3 * 4 * Replaces two small pieces of behaviour that used to come from plugins/ 5 * theme JS this build no longer loads: 6 * 1. Jupiter X "Raven" mobile nav toggle. 7 * 2. JetPopup's open/close handling for the 3 site-wide popups 8 * (gift voucher, gift package, book appointment). 9 * 10 * Everything else interactive (WooCommerce cart/checkout, LatePoint booking 11 * calendar, Contact Form 7 validation/submit) is handled by those plugins' 12 * own scripts, which still load normally since the plugins remain active. 13 */ 14( function () { 15 'use strict'; 16 17 document.addEventListener( 'DOMContentLoaded', function () { 18 19 /* ---------- Mobile nav menu toggle ---------- */ 20 document.addEventListener( 'click', function ( e ) { 21 var toggle = e.target.closest( '.raven-nav-menu-toggle-button' ); 22 if ( toggle ) { 23 document.body.classList.toggle( 'ta-mobile-menu-open' ); 24 } 25 } ); 26 27 /* ---------- Popup open triggers ---------- 28 * Any element carrying one of these classes anywhere on the page 29 * opens the matching popup, mirroring the original JetPopup 30 * "custom selector" trigger settings: 31 * .gift -> #jet-popup-870 (Monetary Value Voucher) 32 * .giftpackage -> #jet-popup-884 (Curated Spa Package) 33 * 34 * "Book Appointment" (.bookappointment) is handled separately below 35 * by a fully independent modal - the JetPopup markup it used to 36 * open relied on that plugin's own CSS classes 37 * (.jet-popup--hide-state etc.), which lose a specificity fight 38 * against the plugin's own hotlinked stylesheet 39 * (.jet-popup.jet-popup--front-mode sets display:flex with higher 40 * specificity than a single-class override here could beat), so 41 * the popup never actually became visible. The new modal uses its 42 * own classes end-to-end, so there's no such conflict possible. 43 */ 44 var triggerMap = { 45 'gift': 'jet-popup-870', 46 'giftpackage': 'jet-popup-884' 47 }; 48 49 function openPopup( id ) { 50 var popup = document.getElementById( id ); 51 if ( ! popup ) { 52 return; 53 } 54 // Toggle the inline style directly (set in footer.php) rather than 55 // relying only on an external stylesheet loading correctly. 56 popup.style.display = 'block'; 57 popup.classList.add( 'ta-popup-open' ); 58 popup.classList.remove( 'jet-popup--hide-state' ); 59 document.body.classList.add( 'ta-popup-active' ); 60 } 61 62 function closePopup( popup ) { 63 if ( ! popup ) { 64 return; 65 } 66 popup.style.display = 'none'; 67 popup.classList.remove( 'ta-popup-open' ); 68 popup.classList.add( 'jet-popup--hide-state' ); 69 document.body.classList.remove( 'ta-popup-active' ); 70 } 71 72 document.addEventListener( 'click', function ( e ) { 73 74 // Open triggers. 75 for ( var cls in triggerMap ) { 76 if ( Object.prototype.hasOwnProperty.call( triggerMap, cls ) ) { 77 var trigger = e.target.closest( '.' + cls ); 78 if ( trigger && ! e.target.closest( '.jet-popup' ) ) { 79 e.preventDefault(); 80 openPopup( triggerMap[ cls ] ); 81 return; 82 } 83 } 84 } 85 86 // Close button. 87 var closeBtn = e.target.closest( '.jet-popup__close-button' ); 88 if ( closeBtn ) { 89 closePopup( closeBtn.closest( '.jet-popup' ) ); 90 return; 91 } 92 93 // Click on the dark overlay (but not the popup content itself). 94 var overlay = e.target.closest( '.jet-popup__overlay, .jet-popup__container-overlay' ); 95 if ( overlay ) { 96 closePopup( overlay.closest( '.jet-popup' ) ); 97 return; 98 } 99 } ); 100 101 // Escape key closes any open popup. 102 document.addEventListener( 'keydown', function ( e ) { 103 if ( e.key === 'Escape' ) { 104 var open = document.querySelector( '.jet-popup.ta-popup-open' ); 105 if ( open ) { 106 closePopup( open ); 107 } 108 } 109 } ); 110 111 /* ---------- Book Appointment modal (independent of JetPopup) ---------- 112 * Fully self-contained: its own classes, its own open/close state, 113 * no shared selectors with the plugin CSS above - so nothing here 114 * can lose a specificity fight the way the old .bookappointment 115 * handling did. */ 116 var taBookingModal = document.getElementById( 'ta-booking-modal' ); 117 118 function openBookingModal() { 119 if ( ! taBookingModal ) { 120 return; 121 }
122 taBookingModal.classList.add( 'is-open' ); 123 taBookingModal.setAttribute( 'aria-hidden', 'false' ); 124 document.body.classList.add( 'ta-modal-open' ); 125 } 126 127 function closeBookingModal() { 128 if ( ! taBookingModal ) { 129 return; 130 } 131 taBookingModal.classList.remove( 'is-open' ); 132 taBookingModal.setAttribute( 'aria-hidden', 'true' ); 133 document.body.classList.remove( 'ta-modal-open' ); 134 } 135 136 document.addEventListener( 'click', function ( e ) { 137 var bookTrigger = e.target.closest( '.bookappointment' ); 138 if ( bookTrigger ) { 139 e.preventDefault(); 140 openBookingModal(); 141 return; 142 } 143 144 if ( e.target.closest( '[data-ta-modal-close]' ) ) { 145 closeBookingModal(); 146 } 147 } ); 148 149 document.addEventListener( 'keydown', function ( e ) { 150 if ( e.key === 'Escape' && taBookingModal && taBookingModal.classList.contains( 'is-open' ) ) { 151 closeBookingModal(); 152 } 153 } ); 154 155 156 /** 157 * Tooltips ("?" icons on the Spa Menu price list). 158 * 159 * These were originally powered by the Happy Addons plugin's own 160 * bundled JS, which depends on WordPress-injected runtime config this 161 * static theme doesn't have. Rather than fight that, this reads the 162 * tooltip text straight out of the icon widget's existing 163 * data-settings attribute (untouched from the original markup) and 164 * shows a small floating box on hover - no external plugin JS needed. 165 */ 166 var taTooltipEl = null; 167 168 function taShowTooltip( trigger ) { 169 var settingsRaw = trigger.getAttribute( 'data-settings' ); 170 if ( ! settingsRaw ) { 171 return; 172 } 173 var settings; 174 try { 175 settings = JSON.parse( settingsRaw ); 176 } catch ( err ) { 177 return; 178 } 179 var text = settings.ha_advanced_tooltip_content; 180 if ( ! text ) { 181 return; 182 } 183 184 if ( ! taTooltipEl ) { 185 taTooltipEl = document.createElement( 'div' ); 186 taTooltipEl.className = 'ta-tooltip'; 187 document.body.appendChild( taTooltipEl ); 188 } 189 taTooltipEl.innerHTML = text; 190 taTooltipEl.style.display = 'block'; 191 192 var rect = trigger.getBoundingClientRect(); 193 var isMobile = window.innerWidth <= 767; 194 var top, left; 195 196 if ( isMobile ) { 197 // position below the icon 198 top = rect.bottom + window.scrollY + 8; 199 left = rect.left + window.scrollX; 200 } else { 201 // position to the right of the icon (matches the original's default) 202 top = rect.top + window.scrollY; 203 left = rect.right + window.scrollX + 10; 204 } 205 taTooltipEl.style.top = top + 'px'; 206 taTooltipEl.style.left = left + 'px'; 207 208 // keep it on-screen horizontally 209 var tooltipRect = taTooltipEl.getBoundingClientRect(); 210 if ( tooltipRect.right > window.innerWidth ) { 211 taTooltipEl.style.left = Math.max( 8, window.innerWidth - tooltipRect.width - 16 ) + 'px'; 212 } 213 } 214 215 function taHideTooltip() { 216 if ( taTooltipEl ) { 217 taTooltipEl.style.display = 'none'; 218 } 219 } 220 221 document.addEventListener( 'mouseover', function ( e ) { 222 var trigger = e.target.closest( '.ha-advanced-tooltip-enable' ); 223 if ( trigger ) { 224 taShowTooltip( trigger ); 225 } 226 } ); 227 228 document.addEventListener( 'mouseout', function ( e ) { 229 var trigger = e.target.closest( '.ha-advanced-tooltip-enable' ); 230 if ( trigger && ! trigger.contains( e.relatedTarget ) ) { 231 taHideTooltip(); 232 } 233 } ); 234 235 /** 236 * FAQ toggle (Curated Spa Package / Monetary Value Voucher product 237 * pages) - a single "See Gift Card FAQs" button that reveals the 238 * whole list at once. 239 */ 240 document.addEventListener( 'click', function ( e ) { 241 var toggle = e.target.closest( '.ta-faq-toggle' ); 242 if ( ! toggle ) { 243 return; 244 } 245 toggle.closest( '.ta-faq-accordion' ).classList.toggle( 'ta-faq-open' ); 246 } ); 247 248 } ); 249} )();
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.