From a0ed2c7e9fac3ec641e484832d020a8ec0b9c7c5 Mon Sep 17 00:00:00 2001 From: Reef Date: Wed, 19 Aug 2026 22:35:51 +0000 Subject: [PATCH] Silent ping for hero carousel: pings in background, animates best city - Pings all 6 servers silently with 2s timeout - Picks the lowest-latency server - GSAP slides the city image in from right with label - Server banner cards stay static (city + country only, no ping UI) --- script.js | 95 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 95 insertions(+) diff --git a/script.js b/script.js index 5f2e48c..5d8b5e3 100644 --- a/script.js +++ b/script.js @@ -428,6 +428,101 @@ var si = 0, renderBlog(); } + /* ---- Silent ping for hero carousel ---- */ + (function() { + var SERVERS = [ + { host: 'meppel.odoo4projects.com', city: 'Amsterdam' }, + { host: 'boston.odoo4projects.com', city: 'Boston' }, + { host: 'manchester.odoo4projects.com', city: 'Manchester' }, + { host: 'mumbai.odoo4projects.com', city: 'Mumbai' }, + { host: 'saopaulo.odoo4projects.com', city: 'S\u00e3o Paulo' }, + { host: 'sydney.odoo4projects.com', city: 'Sydney' } + ]; + var heroImages = { + 'meppel.odoo4projects.com': 'images/holland.webp', + 'boston.odoo4projects.com': 'images/city-boston.jpg', + 'manchester.odoo4projects.com': 'images/england.webp', + 'mumbai.odoo4projects.com': 'images/india.webp', + 'saopaulo.odoo4projects.com': 'images/brazil.webp', + 'sydney.odoo4projects.com': 'images/city-sydney.jpg' + }; + + function pingServer(host) { + return new Promise(function(resolve) { + var start = performance.now(); + var img = new Image(); + var timedOut = false; + var timer = setTimeout(function() { + timedOut = true; img.src = ''; + resolve({ host: host, time: -1 }); + }, 2000); + img.onload = function() { + if (!timedOut) { clearTimeout(timer); resolve({ host: host, time: performance.now() - start }); } + }; + img.onerror = function() { + if (!timedOut) { clearTimeout(timer); resolve({ host: host, time: performance.now() - start }); } + }; + img.src = 'https://' + host + '/favicon.ico?_=' + Date.now() + '_' + Math.random().toString(36).slice(2,6); + }); + } + + function animateHero(city, image) { + var hero = document.querySelector('.hero'); + if (!hero) return; + var bg = hero.querySelector('.hero-bg'); + if (!bg) { + bg = document.createElement('div'); + bg.className = 'hero-bg'; + hero.insertBefore(bg, hero.firstChild); + } + var hasExisting = bg.children.length > 0; + var newEl = document.createElement('div'); + newEl.className = 'hero-bg-slide'; + newEl.style.backgroundImage = "url('" + image + "')"; + bg.appendChild(newEl); + var label = document.createElement('div'); + label.className = 'hero-city-label'; + label.innerHTML = 'Our ' + city + ' server fits your location'; + hero.appendChild(label); + gsap.set(newEl, { x: '100%' }); + gsap.set(label, { x: '150%' }); + var tl = gsap.timeline(); + if (hasExisting) { + var oldEl = bg.children[0]; + gsap.set(oldEl, { x: '0%' }); + tl.to(oldEl, { x: '100%', duration: 3, ease: 'power2.out' }, 0) + .to(newEl, { x: '0%', duration: 3, ease: 'power2.out' }, 0) + .to(label, { x: '0%', duration: 2.5, ease: 'power2.out' }, 0.3) + .call(function() { oldEl.remove(); }); + } else { + tl.to(newEl, { x: '0%', duration: 3, ease: 'power2.out' }, 0) + .to(label, { x: '0%', duration: 2.5, ease: 'power2.out' }, 0.3); + } + } + + /* Ping all servers, pick best, animate hero */ + var results = []; + var pending = SERVERS.length; + SERVERS.forEach(function(s) { + pingServer(s.host).then(function(r) { + results.push(r); + pending--; + if (pending === 0) { + var valid = results.filter(function(x) { return x.time >= 0; }); + if (valid.length === 0) return; + valid.sort(function(a, b) { return a.time - b.time; }); + var best = valid[0]; + var bestServer = SERVERS.filter(function(s) { return s.host === best.host; })[0]; + if (bestServer && heroImages[best.host]) { + var img = new Image(); + img.onload = function() { animateHero(bestServer.city, heroImages[best.host]); }; + img.src = heroImages[best.host]; + } + } + }); + }); + })(); + fetch("blog/index.json?_=" + Date.now()) .then(function (r) { return r.json();