Heray-Was-Here
Server : Apache
System : Linux dal-shared-66.hostwindsdns.com 4.18.0-513.24.1.lve.1.el8.x86_64 #1 SMP Thu May 9 15:10:09 UTC 2024 x86_64
User : krnuyqrm ( 1183)
PHP Version : 7.4.33
Disable Function : NONE
Directory :  /home/krnuyqrm/public_html/performancecurvept.com/

Upload File :
current_dir [ Writeable ] document_root [ Writeable ]

 

Current File : /home/krnuyqrm/public_html/performancecurvept.com/script.js
// Mobile navigation toggle
const hamburger = document.querySelector('.hamburger');
const navMenu = document.querySelector('.nav-menu');

hamburger.addEventListener('click', () => {
    hamburger.classList.toggle('active');
    navMenu.classList.toggle('active');
});

// Close mobile menu when clicking on a link
document.querySelectorAll('.nav-menu a').forEach(link => {
    link.addEventListener('click', () => {
        hamburger.classList.remove('active');
        navMenu.classList.remove('active');
    });
});

// Smooth scrolling for navigation links
document.querySelectorAll('a[href^="#"]').forEach(anchor => {
    anchor.addEventListener('click', function (e) {
        e.preventDefault();
        const target = document.querySelector(this.getAttribute('href'));
        if (target) {
            target.scrollIntoView({
                behavior: 'smooth',
                block: 'start'
            });
        }
    });
});

// Header background change on scroll
window.addEventListener('scroll', () => {
    const header = document.querySelector('.header');
    if (window.scrollY > 100) {
        header.style.background = 'rgba(255, 255, 255, 0.98)';
    } else {
        header.style.background = 'rgba(255, 255, 255, 0.95)';
    }
});

// Intersection Observer for animations
const observerOptions = {
    threshold: 0.1,
    rootMargin: '0px 0px -50px 0px'
};

const observer = new IntersectionObserver((entries) => {
    entries.forEach(entry => {
        if (entry.isIntersecting) {
            entry.target.style.opacity = '1';
            entry.target.style.transform = 'translateY(0)';
        }
    });
}, observerOptions);

// Observe elements for animation
document.addEventListener('DOMContentLoaded', () => {
    const animatedElements = document.querySelectorAll('.feature-card, .about-text');
    
    animatedElements.forEach(el => {
        el.style.opacity = '0';
        el.style.transform = 'translateY(30px)';
        el.style.transition = 'opacity 0.6s ease, transform 0.6s ease';
        observer.observe(el);
    });
});

// Inline required-field errors for contact and schedule forms
document.addEventListener('DOMContentLoaded', () => {
    function setupInlineRequiredErrors(formId) {
        const form = document.getElementById(formId);
        if (!form) return;
        if (form.dataset.inlineRequiredErrorsAttached === 'true') return;
        form.dataset.inlineRequiredErrorsAttached = 'true';
        form.setAttribute('novalidate', 'novalidate');

        const requiredFields = Array.from(form.querySelectorAll('input[required], select[required], textarea[required]'))
            .filter((field) => field.type !== 'hidden');

        function getErrorElement(field) {
            const fieldId = field.id ? `field-error-${field.id}` : '';
            if (fieldId) {
                const existing = form.querySelector(`#${CSS.escape(fieldId)}`);
                if (existing) return existing;
            }

            const errorEl = document.createElement('p');
            errorEl.className = 'field-inline-error';
            if (fieldId) errorEl.id = fieldId;
            errorEl.textContent = 'Please complete this question.';
            errorEl.style.display = 'none';
            errorEl.setAttribute('aria-live', 'polite');

            const formGroup = field.closest('.form-group');
            if (formGroup) {
                formGroup.appendChild(errorEl);
            } else {
                field.insertAdjacentElement('afterend', errorEl);
            }
            return errorEl;
        }

        function isFieldEmpty(field) {
            if (field.tagName === 'SELECT') {
                return !field.value || field.value.trim() === '';
            }
            return field.value.trim() === '';
        }

        function showError(field) {
            const errorEl = getErrorElement(field);
            errorEl.style.display = 'block';
        }

        function hideError(field) {
            const errorEl = getErrorElement(field);
            errorEl.style.display = 'none';
        }

        function validateField(field) {
            if (isFieldEmpty(field)) {
                showError(field);
                return false;
            }
            hideError(field);
            return true;
        }

        function validateAllRequiredFields() {
            let isValid = true;
            requiredFields.forEach((field) => {
                if (!validateField(field)) isValid = false;
            });
            return isValid;
        }

        requiredFields.forEach((field) => {
            field.addEventListener('input', () => validateField(field));
            field.addEventListener('change', () => validateField(field));
            field.addEventListener('blur', () => validateField(field));
        });

        form.addEventListener('submit', (event) => {
            const isValid = validateAllRequiredFields();
            if (!isValid) {
                event.preventDefault();
                const firstInvalid = requiredFields.find((field) => isFieldEmpty(field));
                if (firstInvalid) {
                    firstInvalid.scrollIntoView({ behavior: 'smooth', block: 'center' });
                }
            }
        }, true);

        form.addEventListener('click', (event) => {
            const submitControl = event.target.closest('button[type="submit"], input[type="submit"]');
            if (!submitControl) return;
            const isValid = validateAllRequiredFields();
            if (!isValid) {
                event.preventDefault();
                const firstInvalid = requiredFields.find((field) => isFieldEmpty(field));
                if (firstInvalid) {
                    firstInvalid.scrollIntoView({ behavior: 'smooth', block: 'center' });
                }
            }
        }, true);
    }

    setupInlineRequiredErrors('contactForm');
    setupInlineRequiredErrors('scheduleForm');
});

// Add loading animation
window.addEventListener('load', () => {
    document.body.style.opacity = '0';
    document.body.style.transition = 'opacity 0.5s ease';
    
    setTimeout(() => {
        document.body.style.opacity = '1';
    }, 100);
}); 

// Require hCaptcha completion on form submit
document.addEventListener('DOMContentLoaded', () => {
    function setupCaptchaValidation(formId) {
        const form = document.getElementById(formId);
        if (!form) return;
        if (form.dataset.captchaValidationAttached === 'true') return;

        const captchaContainer = form.querySelector('.h-captcha');
        if (!captchaContainer) return;
        form.dataset.captchaValidationAttached = 'true';

        let errorEl = form.querySelector('[data-error-type="captcha"]');
        if (!errorEl) {
            errorEl = document.createElement('p');
            errorEl.className = 'field-inline-error';
            errorEl.dataset.errorType = 'captcha';
            errorEl.textContent = 'Please complete the captcha before submitting.';
            errorEl.setAttribute('aria-live', 'polite');
            errorEl.style.display = 'none';
            captchaContainer.insertAdjacentElement('afterend', errorEl);
        }

        function getCaptchaToken() {
            // hCaptcha can inject response input inside or outside the form
            const formResponseInput = form.querySelector('textarea[name="h-captcha-response"], input[name="h-captcha-response"]');
            if (formResponseInput && formResponseInput.value.trim()) return formResponseInput.value.trim();

            const globalResponseInput = document.querySelector('textarea[name="h-captcha-response"], input[name="h-captcha-response"]');
            if (globalResponseInput && globalResponseInput.value.trim()) return globalResponseInput.value.trim();

            // Prefer API check when available
            if (window.hcaptcha && typeof window.hcaptcha.getResponse === 'function') {
                const widgetIdAttr = captchaContainer.getAttribute('data-hcaptcha-widget-id');
                if (widgetIdAttr) {
                    const byWidget = window.hcaptcha.getResponse(widgetIdAttr);
                    if (byWidget && byWidget.trim()) return byWidget.trim();
                }
                const firstWidget = window.hcaptcha.getResponse();
                if (firstWidget && firstWidget.trim()) return firstWidget.trim();
            }

            return '';
        }

        function showCaptchaError() {
            errorEl.style.display = 'block';
        }

        function hideCaptchaError() {
            errorEl.style.display = 'none';
        }

        function validateCaptcha() {
            const isValid = getCaptchaToken().length > 0;
            if (isValid) hideCaptchaError();
            else showCaptchaError();
            return isValid;
        }

        function blockSubmission(event) {
            if (event) {
                event.preventDefault();
                event.stopPropagation();
                if (typeof event.stopImmediatePropagation === 'function') {
                    event.stopImmediatePropagation();
                }
            }
            showCaptchaError();
            captchaContainer.scrollIntoView({ behavior: 'smooth', block: 'center' });
        }

        // Capture phase ensures this runs before third-party submit handlers
        form.addEventListener('submit', (event) => {
            if (!validateCaptcha()) {
                blockSubmission(event);
            }
        }, true);

        // Guard submit button clicks in case third-party code bypasses submit event.
        form.addEventListener('click', (event) => {
            const submitControl = event.target.closest('button[type="submit"], input[type="submit"]');
            if (!submitControl) return;
            if (!validateCaptcha()) {
                blockSubmission(event);
            }
        }, true);

        // Guard direct programmatic submits (form.submit / form.requestSubmit)
        const nativeSubmit = form.submit.bind(form);
        form.submit = function() {
            if (!validateCaptcha()) {
                blockSubmission();
                return;
            }
            nativeSubmit();
        };

        if (typeof form.requestSubmit === 'function') {
            const nativeRequestSubmit = form.requestSubmit.bind(form);
            form.requestSubmit = function(submitter) {
                if (!validateCaptcha()) {
                    blockSubmission();
                    return;
                }
                nativeRequestSubmit(submitter);
            };
        }

        form.addEventListener('input', () => {
            if (errorEl.style.display !== 'none') {
                validateCaptcha();
            }
        });

        form.querySelectorAll('button[type="submit"], input[type="submit"]').forEach((submitButton) => {
            submitButton.addEventListener('click', () => {
                validateCaptcha();
            });
        });
    }

    setupCaptchaValidation('contactForm');
    setupCaptchaValidation('scheduleForm');
    window.addEventListener('load', () => {
        setupCaptchaValidation('contactForm');
        setupCaptchaValidation('scheduleForm');
        setTimeout(() => {
            setupCaptchaValidation('contactForm');
            setupCaptchaValidation('scheduleForm');
        }, 1200);
    });
});

Hry