← Kapat
main.js
(function () {
'use strict';
const routeToPhp = {
'/': 'index.php',
'/index.php': 'index.php',
'/dezenfeksiyon-hizmeti': 'dezenfeksiyon-hizmeti.php',
'/dezenfeksiyon-hizmeti.php': 'dezenfeksiyon-hizmeti.php',
'/kurumsal-hasere-kontrolu': 'kurumsal-hasere-kontrolu.php',
'/kurumsal-hasere-kontrolu.php': 'kurumsal-hasere-kontrolu.php',
'/deltrap': 'deltrap.php',
'/deltrap.php': 'deltrap.php',
'/iletisim': 'iletisim.php',
'/iletisim.php': 'iletisim.php',
'/teklif-al': 'teklif-al.php',
'/teklif-al.php': 'teklif-al.php',
'/kvkk': 'kvkk.php',
'/kvkk.php': 'kvkk.php'
};
const phpToClean = {
'index.php': '/',
'dezenfeksiyon-hizmeti.php': '/dezenfeksiyon-hizmeti',
'kurumsal-hasere-kontrolu.php': '/kurumsal-hasere-kontrolu',
'deltrap.php': '/deltrap',
'iletisim.php': '/iletisim',
'teklif-al.php': '/teklif-al',
'kvkk.php': '/kvkk'
};
const pageCache = new Map();
const preloader = document.getElementById('preloader');
const siteHeader = document.querySelector('.site-header');
const scrollTopButton = document.getElementById('scroll-top');
const appBasePath = detectAppBasePath();
let isNavigating = false;
if (window.gsap && window.ScrollTrigger) {
gsap.registerPlugin(ScrollTrigger);
}
function ensureTopBeforeTransition() {
if (window.scrollY <= 4) {
return Promise.resolve();
}
return new Promise((resolve) => {
const startedAt = performance.now();
const maxWait = 900;
window.scrollTo({ top: 0, behavior: 'smooth' });
const check = () => {
const elapsed = performance.now() - startedAt;
if (window.scrollY <= 4 || elapsed >= maxWait) {
window.scrollTo({ top: 0, behavior: 'auto' });
resolve();
return;
}
requestAnimationFrame(check);
};
requestAnimationFrame(check);
});
}
function detectAppBasePath() {
const knownSegments = new Set([
'',
'index.php',
'dezenfeksiyon-hizmeti',
'dezenfeksiyon-hizmeti.php',
'kurumsal-hasere-kontrolu',
'kurumsal-hasere-kontrolu.php',
'deltrap',
'deltrap.php',
'iletisim',
'iletisim.php',
'teklif-al',
'teklif-al.php',
'kvkk',
'kvkk.php'
]);
const segments = window.location.pathname.split('/').filter(Boolean);
const lastSegment = segments[segments.length - 1] ?? '';
if (knownSegments.has(lastSegment)) {
segments.pop();
}
return '/' + segments.join('/');
}
function waitForLoad() {
if (document.readyState === 'complete') {
return Promise.resolve();
}
return new Promise((resolve) => window.addEventListener('load', resolve, { once: true }));
}
function showPreloader() {
if (!preloader) return;
preloader.classList.add('active');
}
function hidePreloader() {
if (!preloader) return;
preloader.classList.remove('active');
}
function toRelativePath(pathname) {
let relative = pathname;
if (appBasePath !== '/' && pathname.startsWith(appBasePath + '/')) {
relative = pathname.slice(appBasePath.length);
} else if (appBasePath !== '/' && pathname === appBasePath) {
relative = '/';
}
if (!relative.startsWith('/')) {
relative = '/' + relative;
}
if (relative.length > 1 && relative.endsWith('/')) {
relative = relative.slice(0, -1);
}
return relative;
}
function toPublicPath(cleanPath) {
if (cleanPath === '/') {
return appBasePath === '/' ? '/' : appBasePath + '/';
}
return (appBasePath === '/' ? '' : appBasePath) + cleanPath;
}
function getPhpFromPath(pathname) {
const relativePath = toRelativePath(pathname);
return routeToPhp[relativePath] || null;
}
function cleanPathFromPhp(phpFile) {
return phpToClean[phpFile] || '/';
}
async function fetchPage(phpFile) {
if (pageCache.has(phpFile)) {
return pageCache.get(phpFile);
}
const response = await fetch(phpFile, { credentials: 'same-origin' });
if (!response.ok) {
throw new Error('Sayfa yüklenemedi: ' + phpFile);
}
const html = await response.text();
const parser = new DOMParser();
const doc = parser.parseFromString(html, 'text/html');
const main = doc.querySelector('main');
if (!main) {
throw new Error('Main içeriği bulunamadı: ' + phpFile);
}
const pageData = {
mainHtml: main.outerHTML,
title: doc.title,
description: doc.querySelector('meta[name="description"]')?.getAttribute('content') || ''
};
pageCache.set(phpFile, pageData);
return pageData;
}
async function preloadAllPages() {
const uniquePages = Array.from(new Set(Object.values(routeToPhp)));
await Promise.all(uniquePages.map((phpFile) => fetchPage(phpFile)));
}
async function animateMainIn(mainElement) {
if (!mainElement || !window.gsap) {
return;
}
gsap.set(mainElement, { y: -42, opacity: 0 });
await new Promise((resolve) => {
gsap.to(mainElement, {
y: 0,
opacity: 1,
duration: 0.32,
ease: 'power2.out',
clearProps: 'transform,opacity',
onComplete: resolve
});
});
}
async function replaceMainContent(mainHtml, options = {}) {
const { animateIn = true } = options;
const parser = new DOMParser();
const doc = parser.parseFromString(mainHtml, 'text/html');
const newMain = doc.querySelector('main');
const currentMain = document.querySelector('main');
if (!newMain || !currentMain) {
return null;
}
if (!window.gsap) {
currentMain.replaceWith(newMain);
return newMain;
}
await new Promise((resolve) => {
gsap.killTweensOf(currentMain);
gsap.to(currentMain, {
y: -42,
opacity: 0,
duration: 0.24,
ease: 'power2.in',
onComplete: resolve
});
});
currentMain.replaceWith(newMain);
if (animateIn) {
await animateMainIn(newMain);
} else {
gsap.set(newMain, { y: -42, opacity: 0 });
}
return newMain;
}
function updateMeta(title, description) {
document.title = title;
const descriptionMeta = document.querySelector('meta[name="description"]');
if (descriptionMeta) {
descriptionMeta.setAttribute('content', description || '');
}
}
function updateActiveNav(cleanPath) {
const navLinks = document.querySelectorAll('.site-header nav a');
navLinks.forEach((link) => {
const href = link.getAttribute('href') || '';
const url = new URL(href, window.location.origin + toPublicPath('/'));
const phpFile = getPhpFromPath(url.pathname);
const linkCleanPath = cleanPathFromPhp(phpFile || 'index.php');
link.classList.toggle('active-nav', linkCleanPath === cleanPath);
});
}
function toggleHeaderScrolledState() {
if (!siteHeader) return;
siteHeader.classList.toggle('scrolled', window.scrollY > 12);
}
function runPageAnimations(options = {}) {
const { skipEntrance = false } = options;
if (!(window.gsap && window.ScrollTrigger)) {
return;
}
ScrollTrigger.getAll().forEach((trigger) => trigger.kill());
const revealItems = document.querySelectorAll('.reveal');
revealItems.forEach((item) => gsap.set(item, { clearProps: 'opacity,transform' }));
requestAnimationFrame(() => {
revealItems.forEach((item, index) => {
const itemTop = item.getBoundingClientRect().top;
const isInInitialViewport = itemTop < window.innerHeight * 0.9;
if (skipEntrance) {
gsap.set(item, { clearProps: 'opacity,transform' });
return;
}
if (isInInitialViewport) {
gsap.fromTo(item, { opacity: 0, y: 14 }, {
opacity: 1,
y: 0,
duration: 0.55,
ease: 'power2.out',
delay: (index % 5) * 0.02,
clearProps: 'opacity,transform'
});
return;
}
gsap.set(item, { opacity: 0, y: 20 });
gsap.to(item, {
opacity: 1,
y: 0,
duration: 0.72,
ease: 'power2.out',
delay: (index % 5) * 0.02,
clearProps: 'opacity,transform',
scrollTrigger: {
trigger: item,
start: 'top 86%',
toggleActions: 'play none none none'
}
});
});
ScrollTrigger.refresh();
setTimeout(() => {
document.querySelectorAll('.reveal').forEach((item) => {
const computed = window.getComputedStyle(item);
if (Number.parseFloat(computed.opacity) === 0) {
gsap.set(item, { clearProps: 'opacity,transform' });
item.style.opacity = '1';
item.style.transform = 'none';
}
});
}, 900);
});
if (skipEntrance) {
return;
}
const heroTitle = document.querySelector('.hero-title');
const heroSub = document.querySelector('.hero-sub');
const heroMedia = document.querySelector('.hero-media');
if (heroTitle && heroSub) {
const heroTimeline = gsap.timeline({ defaults: { ease: 'power3.out' } });
heroTimeline
.from(heroTitle, { y: 30, opacity: 0, duration: 0.8 })
.from(heroSub, { y: 16, opacity: 0, duration: 0.5 }, '-=0.45');
if (heroMedia) {
heroTimeline.from(heroMedia, { y: 20, opacity: 0, duration: 0.6 }, '-=0.4');
}
}
}
function initScrollTop() {
if (!scrollTopButton || scrollTopButton.dataset.bound === 'true') {
return;
}
const toggleScrollTop = () => {
scrollTopButton.classList.toggle('active', window.scrollY > 100);
};
toggleScrollTop();
window.addEventListener('scroll', toggleScrollTop, { passive: true });
scrollTopButton.addEventListener('click', (event) => {
event.preventDefault();
window.scrollTo({ top: 0, behavior: 'smooth' });
});
scrollTopButton.dataset.bound = 'true';
}
function initContactWidget() {
const widget = document.getElementById('contactWidget');
if (!widget || widget.dataset.bound === 'true') return;
const widgetButton = widget.querySelector('.contact-widget-button');
const widgetMenu = widget.querySelector('.contact-widget-menu');
const widgetPrompt = widget.querySelector('.contact-widget-prompt');
const promptClose = widget.querySelector('.prompt-close');
if (!widgetButton || !widgetMenu || !widgetPrompt) return;
let promptDismissed = false;
let promptHideTimer;
const hidePrompt = (options = {}) => {
const { removeNotification = true, dismiss = false } = options;
widgetPrompt.classList.remove('show');
if (promptHideTimer) {
clearTimeout(promptHideTimer);
promptHideTimer = null;
}
if (dismiss) promptDismissed = true;
if (removeNotification) widget.classList.remove('has-notification');
};
const showPrompt = () => {
if (promptDismissed) return;
widget.classList.remove('has-notification');
widgetPrompt.classList.add('show');
promptHideTimer = setTimeout(() => {
widget.classList.add('has-notification');
hidePrompt({ removeNotification: false, dismiss: true });
}, 2000);
};
const toggleWidget = () => {
widget.classList.toggle('active');
if (widget.classList.contains('active')) {
hidePrompt({ removeNotification: true, dismiss: true });
widgetMenu.classList.remove('show-campaign');
}
};
widgetButton.addEventListener('click', toggleWidget);
widgetButton.addEventListener('keydown', (event) => {
if (event.key === 'Enter' || event.key === ' ') {
event.preventDefault();
toggleWidget();
}
});
document.addEventListener('click', (event) => {
if (!widget.contains(event.target) && widget.classList.contains('active')) {
widget.classList.remove('active');
widgetMenu.classList.remove('show-campaign');
}
});
setTimeout(showPrompt, 1000);
if (promptClose) {
promptClose.addEventListener('click', (event) => {
event.stopPropagation();
hidePrompt({ removeNotification: true, dismiss: true });
});
}
widgetPrompt.addEventListener('click', (event) => {
if (event.target !== promptClose) {
widget.classList.add('active');
hidePrompt({ removeNotification: true, dismiss: true });
}
});
widget.querySelectorAll('.campaign-btn, .contact-item a').forEach((element) => {
element.addEventListener('click', () => {
widget.classList.remove('active');
widgetMenu.classList.remove('show-campaign');
});
});
widget.dataset.bound = 'true';
}
function initCallRequestPopup() {
const popup = document.getElementById('callRequestPopup');
const form = document.getElementById('callRequestForm');
if (!popup || !form || popup.dataset.bound === 'true') return;
const loadingMessage = popup.querySelector('.call-popup-loading');
const successMessage = popup.querySelector('.call-popup-success');
const errorMessage = popup.querySelector('.call-popup-error');
const closeElements = popup.querySelectorAll('[data-call-popup-close]');
const resetFeedback = () => {
[loadingMessage, successMessage, errorMessage].forEach((el) => {
if (el) el.style.display = 'none';
});
};
const setFeedback = (state) => {
resetFeedback();
if (state === 'loading' && loadingMessage) loadingMessage.style.display = 'inline-flex';
if (state === 'success' && successMessage) successMessage.style.display = 'inline-flex';
if (state === 'error' && errorMessage) errorMessage.style.display = 'inline-flex';
};
const closePopup = () => {
popup.classList.remove('is-visible');
document.body.classList.remove('call-popup-open');
document.removeEventListener('keydown', handleEscape);
resetFeedback();
};
const handleEscape = (event) => {
if (event.key === 'Escape') closePopup();
};
const openPopup = () => {
form.reset();
form.classList.remove('is-submitting');
resetFeedback();
const timeField = form.querySelector('[name="form_time"]');
if (timeField) timeField.value = Date.now();
popup.classList.add('is-visible');
document.body.classList.add('call-popup-open');
document.addEventListener('keydown', handleEscape);
};
closeElements.forEach((element) => {
element.addEventListener('click', () => {
if (!form.classList.contains('is-submitting')) closePopup();
});
});
document.addEventListener('click', (event) => {
const trigger = event.target.closest('[data-call-popup="true"]');
if (!trigger) return;
event.preventDefault();
openPopup();
});
form.addEventListener('submit', (event) => {
event.preventDefault();
if (!form.checkValidity()) {
form.reportValidity();
return;
}
form.classList.add('is-submitting');
setFeedback('loading');
fetch('forms/call-request.php', {
method: 'POST',
body: new FormData(form)
})
.then((response) => {
if (!response.ok) throw new Error('Request failed');
return response.text();
})
.then(() => {
setFeedback('success');
form.reset();
setTimeout(closePopup, 1800);
})
.catch(() => setFeedback('error'))
.finally(() => form.classList.remove('is-submitting'));
});
popup.dataset.bound = 'true';
}
function initTeklifForm() {
const form = document.getElementById('teklifForm');
if (!form || form.dataset.bound === 'true') return;
form.dataset.bound = 'true';
const timeField = form.querySelector('[name="form_time"]');
if (timeField) timeField.value = Date.now();
const submit = document.getElementById('teklifSubmit');
const feedback = document.getElementById('teklifFeedback');
form.addEventListener('submit', function (e) {
e.preventDefault();
if (!form.checkValidity()) {
form.reportValidity();
return;
}
const label = submit.querySelector('.btn-label');
const loading = submit.querySelector('.btn-loading');
label.hidden = true;
loading.hidden = false;
submit.disabled = true;
if (feedback) feedback.innerHTML = '';
fetch('forms/teklif.php', {
method: 'POST',
body: new FormData(form)
})
.then(function (r) {
if (!r.ok) return r.text().then(function (t) { throw new Error(t); });
return r.text();
})
.then(function () {
if (feedback) feedback.innerHTML = '<div class="teklif-success">✓ Talebiniz alındı! En geç 24 saat içinde sizi arayacağız.</div>';
form.reset();
if (timeField) timeField.value = Date.now();
})
.catch(function (err) {
if (feedback) feedback.innerHTML = '<div class="teklif-error">✕ ' + (err.message || 'Bir hata oluştu. Lütfen tekrar deneyin.') + '</div>';
})
.finally(function () {
label.hidden = false;
loading.hidden = true;
submit.disabled = false;
});
});
}
function initHamburgerMenu() {
const toggle = document.getElementById('navToggle');
const nav = document.getElementById('siteNav');
if (!toggle || !nav) return;
function closeMenu() {
document.body.classList.remove('nav-open');
toggle.setAttribute('aria-expanded', 'false');
}
toggle.addEventListener('click', (e) => {
e.stopPropagation();
const isOpen = document.body.classList.toggle('nav-open');
toggle.setAttribute('aria-expanded', String(isOpen));
});
nav.addEventListener('click', (e) => {
if (e.target.closest('a')) closeMenu();
});
document.addEventListener('click', (e) => {
if (!e.target.closest('.nav-wrap') && document.body.classList.contains('nav-open')) {
closeMenu();
}
});
window.addEventListener('scroll', () => {
if (document.body.classList.contains('nav-open')) closeMenu();
}, { passive: true });
}
function initPersistentUi() {
toggleHeaderScrolledState();
window.addEventListener('scroll', toggleHeaderScrolledState, { passive: true });
initScrollTop();
initContactWidget();
initCallRequestPopup();
initHamburgerMenu();
}
function reinitPageUi(options = {}) {
runPageAnimations(options);
toggleHeaderScrolledState();
initTeklifForm();
}
async function navigateTo(phpFile, options = {}) {
const { push = true, immediate = false } = options;
if (isNavigating) return;
const currentPhp = history.state?.phpFile || getPhpFromPath(window.location.pathname) || 'index.php';
if (phpFile === currentPhp && push) {
return;
}
const shouldScrollBeforeEnter = window.scrollY > 4;
isNavigating = true;
try {
if (!pageCache.has(phpFile) && !immediate) {
showPreloader();
}
const pageData = await fetchPage(phpFile);
const nextMain = await replaceMainContent(pageData.mainHtml, {
animateIn: !shouldScrollBeforeEnter
});
if (shouldScrollBeforeEnter) {
await ensureTopBeforeTransition();
await animateMainIn(nextMain);
}
updateMeta(pageData.title, pageData.description);
const cleanPath = cleanPathFromPhp(phpFile);
const publicPath = toPublicPath(cleanPath);
if (push) {
history.pushState({ phpFile }, '', publicPath);
} else {
history.replaceState({ phpFile }, '', publicPath);
}
updateActiveNav(cleanPath);
reinitPageUi({ skipEntrance: true });
} finally {
hidePreloader();
isNavigating = false;
}
}
function shouldHandleLink(event, link) {
if (!link) return false;
if (link.target === '_blank' || link.hasAttribute('download')) return false;
if (event.metaKey || event.ctrlKey || event.shiftKey || event.altKey) return false;
const href = link.getAttribute('href') || '';
if (href.startsWith('#') || href.startsWith('mailto:') || href.startsWith('tel:')) return false;
const url = new URL(href, window.location.origin + toPublicPath('/'));
if (url.origin !== window.location.origin) return false;
return Boolean(getPhpFromPath(url.pathname));
}
function initRouter() {
document.addEventListener('click', (event) => {
const link = event.target.closest('a[href]');
if (!shouldHandleLink(event, link)) return;
const url = new URL(link.getAttribute('href'), window.location.origin + toPublicPath('/'));
const phpFile = getPhpFromPath(url.pathname);
if (!phpFile) return;
event.preventDefault();
navigateTo(phpFile, { push: true }).catch(() => {
window.location.href = url.pathname;
});
});
window.addEventListener('popstate', () => {
const phpFile = getPhpFromPath(window.location.pathname) || 'index.php';
navigateTo(phpFile, { push: false, immediate: true }).catch(() => {
window.location.reload();
});
});
}
async function boot() {
showPreloader();
initPersistentUi();
initRouter();
const currentPhp = getPhpFromPath(window.location.pathname) || 'index.php';
const currentMain = document.querySelector('main');
const currentDescription = document.querySelector('meta[name="description"]')?.getAttribute('content') || '';
if (currentMain) {
pageCache.set(currentPhp, {
mainHtml: currentMain.outerHTML,
title: document.title,
description: currentDescription
});
}
await Promise.all([waitForLoad(), preloadAllPages()]);
updateActiveNav(cleanPathFromPhp(currentPhp));
reinitPageUi({ skipEntrance: false });
history.replaceState({ phpFile: currentPhp }, '', toPublicPath(cleanPathFromPhp(currentPhp)));
hidePreloader();
}
boot().catch(() => {
hidePreloader();
});
})();