PageSourceSearch

https://q1.com.au/js/common_functions.js

js q1.com.au collected 2026-09-24 23:40:55 UTC 15,197 bytes, 530 lines download raw bytes

1(function ($) {
2
3	"use strict";
4	
5	// Preload
6setTimeout(function() {
7    $('#preloader').addClass('loaded');
8    $('.animate_hero').addClass('is-transitioned'); // Ensure titles animate
9}, 200);
10    
11document.addEventListener("DOMContentLoaded", function() {
12    if (window.innerWidth <= 768) {
13        document.getElementById("preloader").style.display = "none";
14    }
15});
16
17
18	//Header Reveal On Scroll
19	$("header.reveal_header").headroom({
20	    "offset": 50,
21	    "tolerance": 5,
22	    "classes": {
23	        "initial": "animated",
24	        "pinned": "slideDown",
25	        "unpinned": "slideUp"
26	    }
27	});
28
29	// Sticky Header
30$(window).on("scroll", function () {
31    let scrollTop = $(this).scrollTop();
32
33    if ($(window).width() > 768) {
34        // Desktop: Keep sticky behavior
35        if (scrollTop > 1) {
36            $(".fixed_header").addClass("sticky");
37        } else {
38            $(".fixed_header").removeClass("sticky");
39        }
40    } else {
41        // Mobile: Fade out on scroll down
42        let opacity = 1 - scrollTop / 200; // Adjust fade speed (200px = fully transparent)
43        $(".fixed_header").css("opacity", opacity < 0 ? 0 : opacity);
44
45        // Only show header again when reaching the top of the page
46        if (scrollTop === 0) {
47            $(".fixed_header").css("opacity", "1");
48        }
49    }
50});
51$(window).scroll(); // Ensure it applies immediately
52
53
54
55    
56    
57
58	// Scroll animation
59	scrollCue.init({
60	    percentage : 0.85
61	});
62
63	// Opacity mask
64	$('.opacity-mask').each(function(){
65		$(this).css('background-color', $(this).attr('data-opacity-mask'));
66	});
67
68	// Data Background
69	$('.background-image').each(function(){
70		$(this).css('background-image', $(this).attr('data-background'));
71	});
72
73	// Button scroll to
74    $('a[href^="#"].btn_scrollto').on('click', function (e) {
75			e.preventDefault();
76			var target = this.hash;
77			var $target = $(target);
78			$('html, body').stop().animate({
79				'scrollTop': $target.offset().top -60
80			}, 300, 'swing', function () {
81				window.location.hash = target;
82		});
83	});
84
85	// Pinned content
86	const pinnedImages = document.querySelectorAll('.pinned-image');
87	pinnedImages.forEach(pinnedImage => {
88	    const container = pinnedImage.querySelector('.pinned-image__container');
89	    const image = container.querySelector('img');
90	    const overlay = container.querySelector('.pinned-image__container-overlay');
91	    const content = pinnedImage.querySelector('.pinned_over_content');
92	    const tl = gsap.timeline({paused: true});
93	    tl.to(container, {
94	        scale: 1.05,
95	    }, 0);
96	    tl.from(content, {
97	        autoAlpha: 0,
98	    }, 0);
99	    tl.from(overlay, {
100	        autoAlpha: 0,
101	    }, 0);
102	    const trigger = ScrollTrigger.create({
103	        animation: tl,
104	        trigger: pinnedImage,
105	        start: "top center",
106	        markers: false,
107	        pin: false,
108	        scrub: false,
109	    });
110	});
111
112	// Video Play on scroll
113	var $win = $(window);
114	var $sectionvideo = $('#section_video video');
115    var elementTop, elementBottom, viewportTop, viewportBottom;
116
117    function isScrolledIntoView(elem) {
118      elementTop = $(elem).offset().top;
119      elementBottom = elementTop + $(elem).outerHeight();
120      viewportTop = $win.scrollTop();
121      viewportBottom = viewportTop + $win.height();
122      return (elementBottom > viewportTop && elementTop < viewportBottom);
123    }
124    
125    if($sectionvideo.length){
126
127      var loadVideo;
128
129      $sectionvideo.each(function(){
130        $(this).attr('webkit-playsinline', '');
131        $(this).attr('playsinline', '');
132        $(this).attr('muted', 'muted');
133
134        $(this).attr('id','loadvideo');
135        loadVideo = document.getElementById('loadvideo');
136        loadVideo.load();
137      });
138
139      $win.scroll(function () { // video to play when is on viewport 
140      
141        $sectionvideo.each(function(){
142          if (isScrolledIntoView(this) == true) {
143              $(this)[0].play();
144          } else {
145              $(this)[0].pause();
146          }
147        });
148      
149      });
150    }
151	
152	// Menu sidebar panel v1
153	$('.open_close_nav_panel').on("click", function () {
154		$('.nav_panel').toggleClass('show');
155		$('.layer').toggleClass('layer-is-visible');
156	});
157
158	$(".sidebar-navigation nav li a").on('click', function(){		
159		var parentLevel = $(this).parents('ul').length -1;
160		var currentMenu = $(this).closest('ul');
161		var currentListItem = $(this).parent('li');
162		var parentMenu = $('.level-' + parentLevel);
163		var subMenu = $(this).next('ul');
164		if(currentListItem.hasClass('back')) {
165			// back button hit	
166			currentMenu.removeClass('active');
167			parentMenu.removeClass('hidden');
168		} else if (currentListItem.children('ul').length > 0) {
169			// menu item has children - expand the menu
170			subMenu.toggleClass('active');
171			currentMenu.addClass('hidden');
172		}
173	});
174
175	// Menu sidebar panel v2
176	$('.open_close_menu').on("click", function () {
177		$('.main-menu').toggleClass('show');
178		$('.layer').toggleClass('layer-is-visible');
179	});
180
181	// Menu overaly paner panel
182	$('.menu_open').on("click", function () {
183		$('.hamburger').toggleClass('is-active');
184		$('.panel_menu').toggleClass('active');
185		$('body').toggleClass('no_scroll');
186		$('header').toggleClass('header_color');
187	});
188	
189	// Menu hover images
190	$(".wrapper_menu ul li a").each(function() {
191	    $(this).on("mouseover", function() {
192	        $(".wrapper_menu").addClass("hover");
193	        $(".container-item").removeClass("active");
194	        $(this).parent().addClass("active");
195	    }).on("mouseleave", function() {
196	        $(".wrapper_menu").removeClass("hover");
197	    });
198	});
199
200	// Menu v4 + submenu
201	$('a.show-submenu').on("click", function () {
202		$(this).toggleClass("show_normal");
203	});
204
205	// Carousel items 1
206	$('.carousel_item_1').owlCarousel({
207	    center: true,
208	    items:1,
209	    loop:false, 
210	    addClassActive: true,
211	    margin:0,
212	    autoplay:false,
213	    autoplayTimeout:3000,
214		autoplayHoverPause:true,
215		animateOut: 'fadeOut',
216	    responsive:{
217	    	0:{
218	            dots:true
219	        },
220	        991:{
221	            dots:true
222	        }
223	    }
224	});
225
226	// Carousel items centererd generals
227	$('.carousel_item_centered').owlCarousel({    
228	    loop:true,
229	    margin:5,
230	    nav:true,
231	    dots:false,
232	    center:true,
233	    navText: ["<i class='bi bi-arrow-left-short'></i>","<i class='bi bi-arrow-right-short'></i>"],
234	    responsive:{
235	        0:{
236	            items:1
237	        },
238	        600:{
239	            items:2
240	        },
241	        1000:{
242	            items:2
243	        }
244	    }
245	});
246
247	// Carousel items centered rooms
248	$('.carousel_item_centered_rooms').owlCarousel({    
249	    loop:true,
250	    margin:5,
251	    nav:true,
252	    dots:false,
253	    center:true,
254	    navText: ["<i class='bi bi-arrow-left-short'></i>","<i class='bi bi-arrow-right-short'></i>"],
255	    responsive:{
256	        0:{
257	            items:1
258	        },
259	        600:{
260	            items:1
261	        },
262	        991:{
263	            items:2
264	        }
265	    }
266	});
267
268
269	// Carousel items 3
270	$('.carousel_item_3').owlCarousel({    
271	    loop:false,
272	    margin:15,
273	    nav:true,
274	    dots:false,
275	    center:false,
276	    navText: ["<i class='bi bi-arrow-left-short'></i>","<i class='bi bi-arrow-right-short'></i>"],
277	    responsive:{
278	        0:{
279	            items:1
280	        },
281	        600:{
282	            items:2
283	        },
284	        1000:{
285	            items:3
286	        }
287	    }
288	});
289
290	// Carousel testimonials
291	$('.carousel_testimonials').owlCarousel({
292	 	items:1,
293	    loop:true,
294		autoplay:false,
295	    animateIn: 'flipInX',
296		margin:40,
297    	stagePadding:30,
298	    smartSpeed:300,
299	    autoHeight:true,
300	    dots:true,
301		responsiveClass:true,
302	    responsive:{
303	        600:{
304	            items:1
305	        },
306			 1000:{
307	            items:1,
308				nav:false
309	        }
310	    }
311	});
312
313	// Sticky titles
314	$('.fixed_title').theiaStickySidebar({
315		minWidth: 991,
316		additionalMarginTop: 120
317	});
318
319	// Jquery select
320	$('.custom_select select').niceSelect();
321
322	// Footer reveal 
323	if ($(window).width() >= 1024) {
324		$('footer.revealed').footerReveal({
325		shadow: false,
326		opacity:0.6,
327		zIndex: 1
328	});
329	};
330
331	// Links footer hover effect
332    $(".footer_links > ul > li").hover(function() {
333	  $(this).siblings().stop().fadeTo(300, 0.6);
334	  $(this).parent().siblings().stop().fadeTo(300, 0.3); 
335	}, function() { // Mouse out
336	  $(this).siblings().stop().fadeTo(300, 1);
337	  $(this).parent().siblings().stop().fadeTo(300, 1);
338	});
339
340	// Categories hover images/videos
341	$(".cat_nav_hover ul li a").each(function() {
342	    $(this).on("mouseover", function() {
343	        $(".cat_nav_hover").addClass("hover");
344	        $(".container-item").removeClass("active");
345	        $(this).parent().addClass("active");
346	    }).on("mouseleave", function() {
347	        $(".cat_nav_hover").removeClass("hover");
348	    });
349	});
350
351    
352document.addEventListener("DOMContentLoaded", function () {
353    setTimeout(function () {
354        var jarallaxImage = document.querySelector(".jarallax-img");
355        if (jarallaxImage) {
356            jarallaxImage.style.opacity = "1";
357            jarallaxImage.style.transition = "none"; // Remove transition flicker
358        }
359    }, 200);
360});
361
362    
363    
364	//Scroll back to top
365	var progressPath = document.querySelector('.progress-wrap path');
366	var pathLength = progressPath.getTotalLength();
367	progressPath.style.transition = progressPath.style.WebkitTransition = 'none';
368	progressPath.style.strokeDasharray = pathLength + ' ' + pathLength;
369	progressPath.style.strokeDashoffset = pathLength;
370	progressPath.getBoundingClientRect();
371	progressPath.style.transition = progressPath.style.WebkitTransition = 'stroke-dashoffset 10ms linear';
372	var updateProgress = function() {
373	    var scroll = $(window).scrollTop();
374	    var height = $(document).height() - $(window).height();
375	    var progress = pathLength - (scroll * pathLength / height);
376	    progressPath.style.strokeDashoffset = progress;
377	}
378	updateProgress();
379	$(window).scroll(updateProgress);
380	var offset = 50;
381	var duration = 550;
382	$(window).on('scroll', function() {
383	    if (jQuery(this).scrollTop() > offset) {
384	        jQuery('.progress-wrap').addClass('active-progress');
385	    } else {
386	        jQuery('.progress-wrap').removeClass('active-progress');
387	    }
388	});
389	$('.progress-wrap').on('click', function(event) {
390	    event.preventDefault();
391	    jQuery('html, body').animate({ scrollTop: 0 }, duration);
392	    return false;
393	});	
394
395})(jQuery);
396
397
398
399// Book Now Functions for bookingForm (Q1)
400document.querySelectorAll('.bookingForm').forEach(form => {
401  form.addEventListener('submit', function(e) {
402    e.preventDefault();
403
404    const promoCode = form.querySelector('input[name="promo_code"][type="text"]')?.value.trim();
405    const adults   = parseInt(form.querySelector('input[name="adults"]')?.value) || 0;
406    const children = parseInt(form.querySelector('input[name="childs"][type="text"]')?.value) || 0;
407
408    // Prefer the US-formatted mirror stashed by the picker (dataset.mmdd).
409    // If the input is outside the form, fall back to #dates.
410    const datesEl =
411      form.querySelector('input[name="dates"]') ||
412      document.getElementById('dates');
413
414    const raw = (datesEl?.dataset.mmdd || datesEl?.value || '').trim(); // e.g. "09/09/2025 - 09/12/2025" (MM/DD)
415    let checkIn = '', checkOut = '';
416
417    // Split on hyphen / en-dash / em-dash / or the word "to"
418    const parts = raw.split(/\s*(?:-|–|—|\bto\b)\s*/i).filter(Boolean);
419
420    // Strict MM/DD/YYYY -> Date
421    function parseMDY(str) {
422      const m = str.match(/^(\d{1,2})\/(\d{1,2})\/(\d{4})$/);
423      if (!m) return null;
424      const mm = Number(m[1]), dd = Number(m[2]), yyyy = Number(m[3]);
425      const d = new Date(yyyy, mm - 1, dd);
426      return (d && d.getFullYear() === yyyy && d.getMonth() === mm - 1 && d.getDate() === dd) ? d : null;
427    }
428
429    const pad = n => String(n).padStart(2, '0');
430    const toISO = d => `${d.getFullYear()}-${pad(d.getMonth() + 1)}-${pad(d.getDate())}`;
431
432    if (parts.length === 2) {
433      const inDate  = parseMDY(parts[0]) || new Date(parts[0]);  // fallback if mirror missing
434      const outDate = parseMDY(parts[1]) || new Date(parts[1]);
435
436      if (inDate && outDate && !Number.isNaN(inDate.getTime()) && !Number.isNaN(outDate.getTime())) {
437        checkIn  = toISO(inDate);   // YYYY-MM-DD for SiteMinder
438        checkOut = toISO(outDate);
439      }
440    }
441
442    const baseUrl = 'https://book-directonline.com/properties/Q1ResortSpadirect';
443
444    const params = new URLSearchParams();
445    params.set('items[0][adults]', adults);
446    params.set('items[0][children]', children);
447    params.set('items[0][infants]', 0);
448    params.set('currency', 'AUD');
449    params.set('checkInDate', checkIn);
450    params.set('checkOutDate', checkOut);
451    params.set('trackPage', 'yes');
452    if (promoCode) params.set('promocode', promoCode);
453
454    window.location.href = `${baseUrl}?${params.toString()}`;
455  });
456});
457
458
459
460
461
462
463
464// Book Now Functions for bookingForm2
465  document.querySelectorAll('.bookingForm2').forEach(form => {
466    form.addEventListener('submit', function(e) {
467      e.preventDefault();
468
469const promoCode = form.querySelector('input[name="promo_code"][type="text"]')?.value.trim();
470const dateValue = form.querySelector('input[name="date_booking"]')?.value.trim();
471const adults = parseInt(form.querySelector('input[name="adults_booking"][type="text"]')?.value) || 0;
472const children = parseInt(form.querySelector('input[name="childs_booking"][type="text"]')?.value) || 0;
473
474
475      let checkIn = '', checkOut = '';
476      const dates = dateValue.split(' - '); // Format: "11/05/2025 - 14/05/2025"
477      if (dates.length === 2) {
478        const [inStr, outStr] = dates;
479
480        const parseDMY = (str) => {
481          const [day, month, year] = str.split('/').map(Number);
482          return new Date(year, month - 1, day); // month is 0-based
483        };
484
485        const inDate = parseDMY(inStr);
486        const outDate = parseDMY(outStr);
487
488        const formatDate = date => {
489          const year = date.getFullYear();
490          const month = String(date.getMonth() + 1).padStart(2, '0');
491          const day = String(date.getDate()).padStart(2, '0');
492          return `${year}-${month}-${day}`;
493        };
494
495        if (!isNaN(inDate) && !isNaN(outDate)) {
496          checkIn = formatDate(inDate);
497          checkOut = formatDate(outDate);
498        }
499      }
500
501const baseUrl = 'https://book-directonline.com/properties/Q1ResortSpadirect';
502
503const params = new URLSearchParams();
504params.set('locale', 'en');
505params.set('items[0][adults]', adults);
506params.set('items[0][children]', children);
507params.set('items[0][infants]', 0); // You can make this dynamic later if needed
508params.set('currency', 'AUD'); // Change currency if needed
509params.set('checkInDate', checkIn);
510params.set('checkOutDate', checkOut);
511params.set('trackPage', 'yes');
512
513if (promoCode) {
514  params.set('promocode', promoCode); // If SiteMinder supports promo codes
515}
516
517window.location.href = `${baseUrl}?${params.toString()}`;
518
519    });
520  });
521
522
523
524
525// Increase grey color gradually in hero banner section opacity mask
526const mask = document.querySelector('.opacity-mask');
527if (mask) {
528  // Triggers the transition
529  mask.style.setProperty('background-color', 'rgba(0, 0, 0, 0.5)', 'important');
530}

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.