// Enhanced JavaScript for UK Data Services Website
document.addEventListener('DOMContentLoaded', function() {
// Rotating Hero Text Effect (like original UK Data Services site)
const rotatingText = document.getElementById('rotating-text');
const heroSubtitle = document.getElementById('hero-subtitle');
if (rotatingText && heroSubtitle) {
const slides = [
{
title: "Voted UK's No.1 Web Scraping Service",
subtitle: "We are experts in web scraping, data analysis and competitor price monitoring."
},
{
title: "UK-based Team",
subtitle: "Our team is based in the UK for a clearer, faster response."
},
{
title: "Professional Price Monitoring",
subtitle: "Let us monitor your competitor's pricing and product ranges."
},
{
title: "Bespoke Software Solutions",
subtitle: "Let our experts build your ideal scraping solution."
}
];
let currentSlide = 0;
function rotateSlide() {
// Fade out
rotatingText.style.opacity = '0';
heroSubtitle.style.opacity = '0';
setTimeout(() => {
// Change text
rotatingText.textContent = slides[currentSlide].title;
heroSubtitle.textContent = slides[currentSlide].subtitle;
// Fade in
rotatingText.style.opacity = '1';
heroSubtitle.style.opacity = '1';
currentSlide = (currentSlide + 1) % slides.length;
}, 500);
}
// Add transition styles immediately
rotatingText.style.transition = 'opacity 0.5s ease-in-out';
heroSubtitle.style.transition = 'opacity 0.5s ease-in-out';
// Start rotation after a short delay
setTimeout(() => {
rotateSlide();
setInterval(rotateSlide, 4000); // Change every 4 seconds
}, 2000); // Start after 2 seconds
console.log('Hero text rotation initialized');
} else {
console.log('Rotating text elements not found');
}
// Mobile Navigation Toggle
const navToggle = document.getElementById('nav-toggle');
const navMenu = document.getElementById('nav-menu');
if (navToggle && navMenu) {
navToggle.addEventListener('click', function() {
navMenu.classList.toggle('active');
navToggle.classList.toggle('active');
});
// Close mobile menu when clicking on a link
const navLinks = document.querySelectorAll('.nav-link');
navLinks.forEach(link => {
link.addEventListener('click', () => {
navMenu.classList.remove('active');
navToggle.classList.remove('active');
});
});
}
// Navbar Scroll Effect
const navbar = document.getElementById('navbar');
function handleNavbarScroll() {
if (window.scrollY > 50) {
navbar.classList.add('scrolled');
} else {
navbar.classList.remove('scrolled');
}
}
window.addEventListener('scroll', handleNavbarScroll);
// Smooth Scrolling for Navigation Links
const smoothScrollLinks = document.querySelectorAll('a[href^="#"]');
smoothScrollLinks.forEach(link => {
link.addEventListener('click', function(e) {
e.preventDefault();
const targetId = this.getAttribute('href');
const targetSection = document.querySelector(targetId);
if (targetSection) {
const headerOffset = 80;
const elementPosition = targetSection.getBoundingClientRect().top;
const offsetPosition = elementPosition + window.pageYOffset - headerOffset;
window.scrollTo({
top: offsetPosition,
behavior: 'smooth'
});
}
});
});
// Enhanced Scroll Animations
const animatedElements = document.querySelectorAll('.animate-on-scroll, .service-card, .feature, .step');
const observerOptions = {
threshold: 0.1,
rootMargin: '0px 0px -50px 0px'
};
const observer = new IntersectionObserver(function(entries) {
entries.forEach(entry => {
if (entry.isIntersecting) {
entry.target.classList.add('animated');
entry.target.style.opacity = '1';
entry.target.style.transform = 'translateY(0)';
observer.unobserve(entry.target);
}
});
}, observerOptions);
animatedElements.forEach((element, index) => {
// Set initial state
element.style.opacity = '0';
element.style.transform = 'translateY(30px)';
element.style.transition = `opacity 0.8s ease-out ${index * 0.1}s, transform 0.8s ease-out ${index * 0.1}s`;
observer.observe(element);
});
// Add hover animations to service cards
const serviceCards = document.querySelectorAll('.service-card');
serviceCards.forEach(card => {
card.addEventListener('mouseenter', function() {
this.style.transform = 'translateY(-10px) scale(1.02)';
this.style.boxShadow = '0 20px 40px rgba(0, 0, 0, 0.15)';
});
card.addEventListener('mouseleave', function() {
this.style.transform = 'translateY(0) scale(1)';
this.style.boxShadow = '0 4px 20px rgba(0, 0, 0, 0.08)';
});
});
// Add pulse animation to CTA buttons
const ctaButtons = document.querySelectorAll('.btn-primary');
ctaButtons.forEach(btn => {
btn.addEventListener('mouseenter', function() {
this.style.animation = 'pulse 0.5s ease-in-out';
});
btn.addEventListener('mouseleave', function() {
this.style.animation = 'none';
});
});
console.log('Enhanced animations initialized');
// Enhanced Form Validation with Anti-Spam Measures
const contactForm = document.querySelector('.contact-form form');
if (contactForm) {
// Track form interactions for bot detection
let formInteractions = {
mouseMovements: 0,
keystrokes: 0,
focusEvents: 0,
startTime: Date.now(),
fields: {}
};
// Add hidden timestamp field
const timestampField = document.createElement('input');
timestampField.type = 'hidden';
timestampField.name = 'form_timestamp';
timestampField.value = Date.now();
contactForm.appendChild(timestampField);
// Add hidden interaction token
const interactionToken = document.createElement('input');
interactionToken.type = 'hidden';
interactionToken.name = 'interaction_token';
contactForm.appendChild(interactionToken);
// Track mouse movements (humans move mouse)
let mouseMoveHandler = function() {
if (formInteractions.mouseMovements < 100) {
formInteractions.mouseMovements++;
}
};
document.addEventListener('mousemove', mouseMoveHandler);
// Track interactions on form fields
contactForm.querySelectorAll('input, textarea, select').forEach(field => {
field.addEventListener('keydown', function() {
formInteractions.keystrokes++;
if (!formInteractions.fields[field.name]) {
formInteractions.fields[field.name] = {
keystrokes: 0,
changes: 0,
focusTime: 0
};
}
formInteractions.fields[field.name].keystrokes++;
});
field.addEventListener('focus', function() {
formInteractions.focusEvents++;
if (formInteractions.fields[field.name]) {
formInteractions.fields[field.name].focusTime = Date.now();
}
});
field.addEventListener('change', function() {
if (formInteractions.fields[field.name]) {
formInteractions.fields[field.name].changes++;
}
});
});
contactForm.addEventListener('submit', function(e) {
e.preventDefault();
// Calculate interaction score
const timeSpent = Date.now() - formInteractions.startTime;
const interactionScore = calculateInteractionScore(formInteractions, timeSpent);
// Set interaction token
interactionToken.value = btoa(JSON.stringify({
score: interactionScore,
time: timeSpent,
interactions: formInteractions.mouseMovements + formInteractions.keystrokes + formInteractions.focusEvents
}));
// Basic form validation
const formData = new FormData(this);
const name = formData.get('name');
const email = formData.get('email');
const message = formData.get('message');
// Validation
let isValid = true;
const errors = [];
if (!name || name.trim().length < 2) {
errors.push('Please enter a valid name');
isValid = false;
}
if (!email || !isValidEmail(email)) {
errors.push('Please enter a valid email address');
isValid = false;
}
if (!message || message.trim().length < 10) {
errors.push('Please provide more details about your project (minimum 10 characters)');
isValid = false;
}
// Check interaction score (low score = likely bot)
if (interactionScore < 30) {
errors.push('Please complete the form normally');
isValid = false;
}
if (isValid) {
// Show loading state
const submitButton = this.querySelector('button[type="submit"]');
const originalText = submitButton.textContent;
submitButton.textContent = 'Sending...';
submitButton.disabled = true;
// Submit form with XMLHttpRequest header
fetch('contact-handler.php', {
method: 'POST',
body: formData,
headers: {
'X-Requested-With': 'XMLHttpRequest'
}
})
.then(response => response.json())
.then(data => {
if (data.success) {
showNotification(data.message || 'Message sent successfully! We\'ll get back to you soon.', 'success');
this.reset();
// Reset interaction tracking
formInteractions = {
mouseMovements: 0,
keystrokes: 0,
focusEvents: 0,
startTime: Date.now(),
fields: {}
};
} else {
showNotification(data.message || 'There was an error sending your message. Please try again.', 'error');
}
})
.catch(error => {
console.error('Error:', error);
showNotification('There was an error sending your message. Please try again.', 'error');
})
.finally(() => {
submitButton.textContent = originalText;
submitButton.disabled = false;
});
} else {
showNotification(errors.join('
'), 'error');
}
});
}
// Calculate interaction score to detect bots
function calculateInteractionScore(interactions, timeSpent) {
let score = 0;
// Time-based scoring (bots submit too fast)
if (timeSpent > 5000) score += 20; // More than 5 seconds
if (timeSpent > 10000) score += 20; // More than 10 seconds
if (timeSpent > 30000) score += 10; // More than 30 seconds
// Mouse movement scoring (humans move mouse)
if (interactions.mouseMovements > 10) score += 20;
if (interactions.mouseMovements > 50) score += 10;
// Keystroke scoring (humans type)
if (interactions.keystrokes > 20) score += 20;
if (interactions.keystrokes > 50) score += 10;
// Focus event scoring (humans tab/click between fields)
if (interactions.focusEvents > 3) score += 10;
return Math.min(score, 100); // Cap at 100
}
// Email validation function
function isValidEmail(email) {
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
return emailRegex.test(email);
}
// Notification system
function showNotification(message, type = 'info') {
// Remove existing notifications
const existingNotification = document.querySelector('.notification');
if (existingNotification) {
existingNotification.remove();
}
// Create notification element
const notification = document.createElement('div');
notification.className = `notification notification-${type}`;
notification.innerHTML = `