1// Exit intent detection based on mouse movement patterns 2let lastMousePosition = { x: 0, y: 0 }; 3let lastMouseMoveTime = 0; 4let lastActivityTime = Date.now(); 5let exitIntentDetected = false; 6let cornerDetectionTimeout = null; 7let afkTimeout = null; 8 9// Configuration 10const CORNER_THRESHOLD = 50; // pixels from corner to consider it a corner 11const MOVEMENT_THRESHOLD = 3; // minimum pixels to consider it a movement 12const TIME_THRESHOLD = 3000; // 3 seconds to detect slow movement 13const SLOW_MOVEMENT_THRESHOLD = 100; // pixels per second to consider it slow movement 14const AFK_THRESHOLD = 240000; // 4 minutes in milliseconds 15 16// Check if device is a touch-only mobile device 17function isTouchOnlyDevice() { 18 // Check if device has touch capability 19 const hasTouch = 'ontouchstart' in window || navigator.maxTouchPoints > 0; 20 21 // Check if device is a mobile device (excluding tablets and laptops with touch) 22 const isMobile = /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent); 23 24 // Check if device has a keyboard (laptops/desktops) 25 const hasKeyboard = navigator.keyboard !== undefined; 26 27 // Device is touch-only if it has touch, is mobile, and doesn't have a keyboard 28 return hasTouch && isMobile && !hasKeyboard; 29} 30 31function sendExitIntentToUnity() { 32 if (typeof unityInstance !== 'undefined') { 33 unityInstance.SendMessage('WebUtils', 'OnExitIntent'); 34 } 35} 36 37function initExitIntentDetection() { 38 // Only initialize if not a touch-only device 39 if (isTouchOnlyDevice()) { 40 console.log("[exit-intent] Touch-only device detected, exit intent detection disabled"); 41 return; 42 } 43 44 console.log("[exit-intent] Desktop device detected, exit intent detection enabled"); 45 document.addEventListener('mousemove', handleMouseMove); 46 document.addEventListener('mouseleave', handleMouseLeave); 47 document.addEventListener('keydown', handleActivity); 48 document.addEventListener('click', handleActivity); 49 50 // Start AFK timer 51 resetAFKTimer(); 52} 53 54function handleActivity() { 55 lastActivityTime = Date.now(); 56 resetAFKTimer(); 57} 58 59function resetAFKTimer() { 60 // Clear existing AFK timeout if any 61 if (afkTimeout) { 62 clearTimeout(afkTimeout); 63 } 64 65 // Set new AFK timeout 66 afkTimeout = setTimeout(() => { 67 if (!exitIntentDetected) { 68 exitIntentDetected = true; 69 console.log("[exit-intent] AFK exit intent detected after 4 minutes of inactivity"); 70 sendExitIntentToUnity(); 71 } 72 }, AFK_THRESHOLD); 73} 74 75function handleMouseMove(e) { 76 const currentTime = Date.now(); 77 const timeDiff = currentTime - lastMouseMoveTime; 78 79 // Update last activity time 80 lastActivityTime = currentTime; 81 resetAFKTimer(); 82 83 // Calculate movement speed 84 const distance = Math.sqrt( 85 Math.pow(e.clientX - lastMousePosition.x, 2) + 86 Math.pow(e.clientY - lastMousePosition.y, 2) 87 ); 88 const speed = distance / (timeDiff / 1000); // pixels per second 89 90 // Check if mouse is in a corner and moving slowly 91 const isInCorner = isMouseInCorner(e.clientX, e.clientY); 92 const isMovingSlowly = speed < SLOW_MOVEMENT_THRESHOLD && distance > MOVEMENT_THRESHOLD; 93 94 if (isInCorner && isMovingSlowly && !exitIntentDetected) { 95 if (!cornerDetectionTimeout) { 96 cornerDetectionTimeout = setTimeout(() => { 97 if (isMouseInCorner(e.clientX, e.clientY)) { 98 exitIntentDetected = true; 99 console.log("[exit-intent] Corner exit intent detected - mouse moved slowly to corner for 3 seconds"); 100 sendExitIntentToUnity(); 101 } 102 }, TIME_THRESHOLD); 103 } 104 } else if (!isInCorner || !isMovingSlowly) { 105 // Reset detection if mouse moves out of corner or moves too fast 106 if (cornerDetectionTimeout) { 107 clearTimeout(cornerDetectionTimeout); 108 cornerDetectionTimeout = null; 109 } 110 exitIntentDetected = false; 111 } 112 113 // Update last position and time 114 lastMousePosition = { x: e.clientX, y: e.clientY }; 115 lastMouseMoveTime = currentTime; 116} 117 118function handleMouseLeave(e) { 119 // If mouse leaves through the top, consider it an exit intent 120 if (e.clientY <= 0) { 121 console.log("[exit-intent] Mouse left through top of window"); 122 sendExitIntentToUnity(); 123 } 124} 125 126function isMouseInCorner(x, y) { 127 const windowWidth = window.innerWidth; 128 const windowHeight = window.innerHeight; 129 130 // Check top-left corner 131 if (x <= CORNER_THRESHOLD && y <= CORNER_THRESHOLD) { 132 return true; 133 } 134 135 // Check top-right corner 136 if (x >= windowWidth - CORNER_THRESHOLD && y <= CORNER_THRESHOLD) { 137 return true; 138 } 139 140 return false;
141} 142 143// Initialize when the script loads 144initExitIntentDetection();
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.