// ==UserScript== // @name Back to Home (39C3 Kiosk) // @namespace http://tampermonkey.net/ // @version 2025-12-18 // @description Adds buttons to every website to return to home page and prompts on idle // @author You // @match *://*/* // @icon https://www.google.com/s2/favicons?sz=64&domain=google.com // @grant GM_addStyle // ==/UserScript== const target = "https://kiosk.39c3.by.vincent.mahn.ke/"; (function() { 'use strict'; // if the user is on target already or subdomain, do nothing if (window.location.href === target || window.location.href.startsWith(target + '/')) { return; } const btn = document.createElement('button'); btn.textContent = 'Home'; btn.style.cssText = ' all: unset; box-sizing: border-box; border: 2px solid #141414; background: #faf5f5; text-align: center; color: #141414; position: fixed; right: 10px; bottom: 10px; width: 60px; height: 60px; z-index: 2147483647; padding-top: 6px; border-radius: 60px;'; btn.innerHTML = ''; btn.addEventListener('click', () => { window.location.href = target; }); (document.body || document.documentElement).appendChild(btn); const IDLE_LIMIT_MS = 60_000; let idleTimer = null; let promptVisible = false; const PROMPT_LIMIT_MS = 30_000; let promptInterval = null; let promptTimeout = null; const modal = document.createElement('div'); modal.id = 'idle-modal'; modal.hidden = true; modal.style.cssText = ` position: fixed; top: 50%; left: 50%; transform: translate(-50%, -50%); background-color: #141414 !important; border-radius: 0.385em; border: 2px solid #444; padding: 20px; z-index: 2147483647; box-shadow: 0 4px 8px rgba(0,0,0,0.2); `; modal.innerHTML = `

You seem to be idle

Do you want to stay on this page or go back to the home page?

Auto return in 30s

`; document.body.appendChild(modal); const backdrop = document.createElement('div'); backdrop.id = 'idle-backdrop'; backdrop.hidden = true; backdrop.style.cssText = ` position: fixed; top: 0; left: 0; width: 100%; height: 100%; background: rgba(0,0,0,0.5); z-index: 2147483646; `; document.body.appendChild(backdrop); const userEvents = [ 'mousemove', 'mousedown', 'keydown', 'wheel', 'touchstart', 'scroll' ]; function showPrompt() { promptVisible = true; modal.hidden = false; backdrop.hidden = false; // Clear any previous prompt timers if (promptInterval) { clearInterval(promptInterval); promptInterval = null; } if (promptTimeout) { clearTimeout(promptTimeout); promptTimeout = null; } // Wire button actions (once to avoid duplicates) const stayBtn = document.querySelector("#idle-stay"); const goBtn = document.querySelector("#idle-go"); if (stayBtn) { stayBtn.addEventListener("click", () => { hidePrompt(); resetIdleTimer(); }, { once: true }); } if (goBtn) { goBtn.addEventListener("click", () => { window.location.href = target; }, { once: true }); } // 30s countdown visible to the user let remaining = PROMPT_LIMIT_MS / 1000; // seconds const countdownEl = document.querySelector("#idle-countdown"); if (countdownEl) countdownEl.textContent = String(remaining); promptInterval = setInterval(() => { remaining -= 1; if (remaining >= 0 && countdownEl) { countdownEl.textContent = String(remaining); } }, 1000); // Auto-go when expired promptTimeout = setTimeout(() => { const go = document.querySelector("#idle-go"); if (go) { go.click(); } else { window.location.href = target; } }, PROMPT_LIMIT_MS); } function hidePrompt() { promptVisible = false; modal.hidden = true; backdrop.hidden = true; if (promptInterval) { clearInterval(promptInterval); promptInterval = null; } if (promptTimeout) { clearTimeout(promptTimeout); promptTimeout = null; } } function onIdle() { showPrompt(); } function resetIdleTimer() { if (promptVisible) return; // Don't auto-dismiss while prompt is visible if (idleTimer) clearTimeout(idleTimer); idleTimer = setTimeout(onIdle, IDLE_LIMIT_MS); } // Any user activity resets the timer userEvents.forEach(evt => { document.addEventListener(evt, resetIdleTimer, { passive: true }); }); // When returning to a visible tab, refresh the timer document.addEventListener('visibilitychange', () => { if (document.visibilityState === 'visible') { resetIdleTimer(); } }); // Actions // Kick things off resetIdleTimer(); })();