PageSourceSearch

https://tirtaayuspa.com.ng/vi/wp-content/themes/tirta-ayu-vi-theme/assets/js/theme.js?ver=1790541552

js tirtaayuspa.com.ng collected 2026-10-04 18:54:56 UTC 8,123 bytes, 249 lines download raw bytes

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.