PageSourceSearch

https://altdorfs.com/js/main.js

js altdorfs.com collected 2026-09-29 07:25:27 UTC 13,608 bytes, 479 lines download raw bytes

1/* --------------------------------------------
2  DOCUMENT.READY
3--------------------------------------------- */
4
5window.addEventListener("load", () => {
6	const hiddenElements = document.querySelectorAll(".hidden");
7
8	hiddenElements.forEach((element) => {
9		element.classList.remove("hidden");
10		element.style.opacity = 0;
11		element.style.transition = `opacity 1s ease-in-out`;
12		setTimeout(() => {
13			element.style.opacity = 1;
14		}, 0);
15	});
16});
17
18gsap.registerPlugin(ScrollTrigger, EasePack, CSSRulePlugin, Flip);
19var mobile = Modernizr.mq("(max-width: 992px)");
20
21var path = window.location.pathname.toString();
22var url = window.location.href.toString();
23var pathProto = path.split("/");
24var pathUrl = url.split("//");
25if (pathProto[2] === "proto") {
26    var proto = pathProto[3].toString();
27    if (pathProto[4] === "home" || pathProto[1] === "home") {
28        window.location.replace("https://legacy-admin.spillover.com/spillover/proto/" + proto + "/");
29    }
30} else if (pathProto[2] === "designs") {
31    var proto = pathProto[3].toString();
32    if (pathProto[4] === "home" || pathProto[1] === "home") {
33        window.location.replace("https://legacy-admin.spillover.com/spillover/designs/" + proto + "/");
34    }
35} else {
36    var protoBefore = pathUrl[1].split(".");
37    var proto = protoBefore[0].toString();
38
39    if (pathProto[4] === "home" || pathProto[1] === "home") {
40        window.location.replace(location.protocol + "//" + location.host);
41    }
42}
43
44let $scrollElement = $(window);
45let $mainNavbar = $("#mainNavbar");
46let scrollTopDistance;
47function toggleScrolledClass() {
48    if (scrollTopDistance > 10 || (mobile && scrollTopDistance > -1)) {
49        $mainNavbar.addClass("scrolled");
50    } else {
51        $mainNavbar.removeClass("scrolled");
52    }
53}
54
55$(window).on("load scroll resize", function (e) {
56    scrollTopDistance = window.pageYOffset;
57    mobile = window.outerWidth <= 992;
58    toggleScrolledClass();
59});
60
61// Hero
62
63const hero = document.querySelector("#hero .uk-overlay");
64const cta = document.querySelectorAll(".cta");
65const ctaWrap = document.querySelectorAll(".cta-content-wrap");
66const homeItems = gsap.utils.toArray("#home p, #home h2, #home img");
67const contactInfoElements = $("#contact .contact-info");
68const contactIframeElements = $("#contact iframe");
69const reviewsIframeElements = $("#reviews .uk-slider-container");
70const headerLogo = $("#mainNavbar .navbar-brand");
71const headerNav = $("#mainNavbar .navbar-nav");
72const footerCopyright = $(".spillover img");
73const footerSpillover = $("#footer .copyright p");
74
75gsap.to(hero, {
76    autoAlpha: 0,
77    ease: "power1.out",
78    scrollTrigger: {
79        trigger: "#hero",
80        start: "top top",
81        end: "bottom top",
82        scrub: true,
83        onUpdate: function () {
84            if (scrollTopDistance <= 10) {
85                gsap.set(hero, { autoAlpha: 1 });
86            }
87            ScrollTrigger.update();
88        },
89    },
90});
91
92// Call To Action/Promotiles
93
94cta.forEach((element) => {
95    const speed = parseFloat(element.dataset.speed) || 1;
96    const ticker = gsap.ticker;
97
98    let targetY = 0;
99    let currentY = 0;
100
101    ticker.add(() => {
102        currentY += (targetY - currentY) * 0.05;
103        gsap.set(element, {
104            y: -currentY * speed,
105            rotation: 0.01,
106            force3D: true,
107            transform: `translateZ(0)`,
108            backfaceVisibility: `hidden`,
109        });
110    });
111
112    $scrollElement.on("scroll", function () {
113        targetY = scrollTopDistance * 0.1;
114    });
115});
116
117// Optimize CTA wrap animation
118gsap.set(ctaWrap, { autoAlpha: 0, y: 250 });
119ScrollTrigger.batch(ctaWrap, {
120    start: "top 120%", // Adjusted start value for earlier appearance on desktop
121    end: "0% 100%",
122    onEnter: (batch) => {
123        gsap.to(batch, { autoAlpha: 1, y: 0, duration: 1, ease: "power1.out" });
124    },
125});
126
127// Home
128
129function animateHomeItem(element, speed, offsetY) {
130    const ticker = gsap.ticker;
131
132    let targetY = 0;
133    let currentY = 0;
134
135    ticker.add(() => {
136        currentY += (targetY - currentY) * 0.05;
137        gsap.set(element, {
138            y: (-currentY + offsetY) * speed,
139            rotation: 0.01,
140            force3D: true,
141            transform: `translateZ(0)`,
142            backfaceVisibility: `hidden`,
143        });
144    });
145
146    $scrollElement.on("scroll", function () {
147        targetY = scrollTopDistance * 0.1;
148    });
149}
150
151if (mobile) {
152    homeItems.forEach((element) => {
153        const speed = parseFloat(element.dataset.speed) || 1;
154        animateHomeItem(element, speed, 125);
155    });
156} else {
157    homeItems.forEach((element) => {
158        const speed = parseFloat(element.dataset.speed) || 1;
159        animateHomeItem(element, speed, 220);
160    });
161}
162
163// Contact
164
165$(document).ready(() => {
166    // Check if jQuery and GSAP are loaded
167    if (typeof $ === "undefined" || typeof gsap === "undefined") {
168        console.error("jQuery and/or GSAP not loaded");
169        return;
170    }
171
172    function animateElements(elements, xOffset, yOffset) {
173		elements.each(function () {
174			const element = this;
175			const isAboveViewport = element.getBoundingClientRect().bottom < 0;
176
177			gsap.set(element, {
178				autoAlpha: isAboveViewport ? 1 : 0,
179				x: isAboveViewport ? 0 : xOffset,
180				y: isAboveViewport ? 0 : yOffset
181			});
182		});
183
184		ScrollTrigger.batch(elements, {
185			start: "top bottom",
186			once: true,
187			onEnter: (batch) => {
188				gsap.to(batch, {
189					autoAlpha: 1,
190					x: 0,
191					y: 0,
192					ease: "power1.out",
193					duration: 1.5
194				});
195			}
196		});
197	}
198
199    function animateElementsOnce(elements, xOffset, yOffset) {
200        gsap.set(elements, { autoAlpha: 0, x: xOffset, y: yOffset, ease: "power1.out" });
201        gsap.to(elements, {
202            delay: 1,
203            duration: 1,
204            autoAlpha: 1,
205            x: 0,
206            y: 0,
207            ease: "power1.out",
208        });
209    }
210
211    animateElements(contactInfoElements, -500, 0);
212    animateElements(contactIframeElements, 500, 0);
213    animateElements(reviewsIframeElements, 0, 500);
214    if (!$("body").hasClass("internal")) {
215        animateElementsOnce(headerLogo, -500, 0);
216        animateElementsOnce(headerNav, 500, 0);
217    }
218    animateElements(footerCopyright, 500, 0);
219    animateElements(footerSpillover, -500, 0);
220});
221
222
223window.addEventListener("load", () => {
224	// Forms
225
226	const modalControlLabels = $(".modal .control-label");
227	modalControlLabels.each(function () {
228		$(this).removeAttr("style").removeClass("col-sm-3 col-form-label");
229		const label = $(this).attr("for");
230		$(this).insertAfter(`.modal #${label}`);
231	});
232	modalControlLabels.promise().done(function () {
233		modalControlLabels.each(function () {
234			const label = $(this).attr("for");
235			const elementsWithSameLabel = $(`.modal [for=${label}]`);
236			if (elementsWithSameLabel.length > 1) {
237				elementsWithSameLabel.first().remove();
238			}
239		});
240	});
241
242	const toastContainer = $(".toast-container");
243
244	toastContainer
245		.find(".control-label")
246		.each(function () {
247			$(this).removeAttr("style").removeClass("col-sm-3 col-form-label");
248			const label = $(this).attr("for");
249			$(this).insertAfter(toastContainer.find(`#${label}`));
250		})
251		.promise()
252		.done(function () {
253			toastContainer.find(".control-label").each(function () {
254				const label = $(this).attr("for");
255				if (toastContainer.find(`[for=${label}
255]`).length > 1) {
256					toastContainer.find(`[for=${label}]`).first().remove();
257				}
258			});
259		});
260
261	const $mainControlLabels = $("main .control-label");
262	$mainControlLabels.each(function () {
263		$(this).removeAttr("style").removeClass("col-sm-3 col-form-label");
264		const label = $(this).attr("for");
265		$(this).insertAfter(`main #${label}`);
266	});
267	$mainControlLabels.promise().done(function () {
268		$mainControlLabels.each(function () {
269			const label = $(this).attr("for");
270			const $duplicateLabels = $(`main [for=${label}]`).not(this);
271			if ($duplicateLabels.length > 0) {
272				$duplicateLabels.remove();
273			}
274		});
275	});
276
277	setTimeout(function () {
278		$(".cmsform .form-group").each(function () {
279			$(this).addClass("mb-3");
280			var checkRadio = $(this).find(".cmsform .form-check").length;
281			var hasButton = $(this).find("button").length;
282			var spanChild = $(this).children('span[data-forfield="resume"]').length;
283			var checkChild = $(this).children("div.form-check").length;
284			if (checkRadio === 0 && spanChild === 0 && hasButton === 0 && checkChild === 0) {
285				$(this).addClass("form-floating");
286				$(this).children(".cmsform label").wrapInner('<span class="formTextColor"></span>');
287			}
288			if (hasButton !== 0) {
289				$(this).removeClass("mb-3");
290			}
291		});
292		$(".hidden-form").fadeIn(1000).removeClass("hidden-form");
293
294		$(".cmsform .form-control:not([placeholder])").each(function () {
295			$(this).attr("placeholder", " ");
296		});
297
298		$(".cmsform .form-check-input").each(function () {
299			$(this).attr("style", "");
300		});
301
302		$(".cmsform textarea.form-control").each(function () {
303			$(this).attr("rows", "3");
304		});
305	}, 500);
306
307	$.datepicker.setDefaults({
308		minDate: 0,
309	});
310
311	//replace these with the id's of your datepickers
312	$('input[name="event-date"]').datepicker({
313		beforeShowDay: function (date) {
314			let day = date.getDay();
315			let string = jQuery.datepicker.formatDate("d-m-yy", date);
316			let isDisabled = $.inArray(string, disabledDays) != -1;
317
318			//day != 0 disables all Sundays
319			return [day != 0 && !isDisabled];
320		},
321	});
322
323	const socialIcons = gsap.utils.toArray(".social li");
324	gsap.set(socialIcons, { autoAlpha: 0, x: gsap.utils.random(-100, 100) });
325
326	const scrollTriggerOptions = {
327		start: "top 100%",
328		end: "bottom 0%",
329		onEnter: (batch) => {
330			gsap.to(batch, { autoAlpha: 1, stagger: 0.05, x: 0 });
331		},
332	};
333
334	ScrollTrigger.batch(socialIcons, scrollTriggerOptions);
335
336	const bottomNavs = gsap.utils.toArray("#footer .nav-item");
337	gsap.set(bottomNavs, { autoAlpha: 0, y: gsap.utils.random(-100, 100) });
338	const bottomNavsTriggerOptions = {
339		start: "top bottom",
340		end: "bottom top",
341		onEnter: (batch) => {
342			gsap.to(batch, { autoAlpha: 1, stagger: 0.05, y: 0 });
343		},
344	};
345
346	ScrollTrigger.batch(bottomNavs, bottomNavsTriggerOptions);
347
348	// Internal Pages
349	const excludedPaths = ["calendar", "menu", "food-menu", "beer-and-wine", "gallery", "", "index.htm", "/"];
350	if (!excludedPaths.includes(pathProto[1]) && !excludedPaths.includes(pathProto[4])) {
351		const internalTitles = gsap.utils.toArray(
352			".internal #main .container > div, .internal #main .container > div > div"
353		);
354		gsap.set(internalTitles, { autoAlpha: 0, x: gsap.utils.random(-100, 100), y: gsap.utils.random(-100, 100) });
355
356		const triggerStart = mobile ? "top 100%" : "top 98%";
357		const triggerEnd = mobile ? "bottom 0%" : "bottom 2%";
358
359		ScrollTrigger.batch(internalTitles, {
360			start: triggerStart,
361			end: triggerEnd,
362			onEnter: (batch) => {
363				gsap.to(batch, { autoAlpha: 1, stagger: 0.1, x: 0, y: 0 });
364			},
365		});
366	}
367
368	gsap.delayedCall(mobile ? 1.5 : 1, () => {
369		ScrollTrigger.refresh(true);
370	});
371});
372
373// Gallery
374
375window.addEventListener("load", () => {
376	let galleryIsotope = $(".gallery-items").isotope({
377		itemSelector: ".gallery-item",
378		layoutMode: "masonry",
379		containerStyle: {
380			overflow: "hidden",
381			position: "relative",
382		},
383		filter: $(".gallery-filters li:first-child").attr("data-filter"),
384	});
385
386	$(".gallery-filters li").on("click", function () {
387		let galleryFilters = $(".gallery-filters li");
388		galleryFilters.each(function () {
389			$(this).removeClass("filter-active");
390		});
391		$(this).addClass("filter-active");
392		let filter = $(this).attr("data-filter");
393		galleryIsotope.isotope({
394			filter: filter,
395		});
396	});
397
398	galleryIsotope.on("arrangeComplete", function () {
399		$(".gallery-item:hidden").removeClass("mag");
400		$(".gallery-item:visible").addClass("mag");
401	});
402
403	galleryIsotope.magnificPopup({
404		type: "image",
405		delegate: "a.mag",
406		gallery: {
407			enabled: true,
408		},
409		zoom: {
410			enabled: true,
411			duration: 300,
412			opener: function (e) {
413				return e.find("img");
414			},
415		},
416	});
417
418	let $galleryContainer = $(".gallery-items");
419	let $galleryImgs = $("img");
420
421	$galleryContainer.imagesLoaded(function () {
422		galleryIsotope.isotope({
423			itemSelector: ".gallery-item",
424		});
425		$galleryImgs.on("load", function () {
426			galleryIsotope.isotope("layout");
427		});
428	});
429});
430
431// Refreshes Menu Tabs When Tabbing Through Them
432
433$(".nav-link").on("click", function () {
434	ScrollTrigger.refresh(true);
435});
436
437// =============================================
438// Mailing List Cookie
439// =============================================
440
441let alreadyShowing = false;
442const mailingToast = $("#mailingListToast");
443let mailingListCookieName = proto + "-mailingList";
444const toast = new bootstrap.Toast(mailingToast);
445
446if (Cookies.get(mailingListCookieName) == null || Cookies.get(mailingListCookieName) != "false") {
447	Cookies.set(mailingListCookieName, "true", {
448		expires: 7,
449	});
450}
451$(document).on("scroll", function () {
452	if ($(this).scrollTop() > 500 && Cookies.get(mailingListCookieName) == "true" && alreadyShowing == false) {
453		toast.show();
454		alreadyShowing = true;
455	}
456});
457$("#mailingListModal button").on("click", function () {
458	Cookies.set(mailingListCookieName, "false", {
459		expires: 1,
460	});
461});
462$("#mailingListToast button").on("click", function () {
463	Cookies.set(mailingListCookieName, "false", {
464		expires: 1,
465	});
466});
467$("#mailingListToast .btn.btn-template").on("click", function () {
468	toast.hide();
469});
470$('#mailingListModal button[type="submit"]').on("click", function () {
471	Cookies.set(mailingListCookieName, "false", {
472		expires: 180,
473	});
474});
475$('#mailingListToast button[type="submit"]').on("click", function () {
476	Cookies.set(mailingListCookieName, "false", {
477		expires: 180,
478	});
479});

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.