Skip to content

Instantly share code, notes, and snippets.

@simonw
Created August 28, 2024 21:49
Show Gist options
  • Save simonw/cd3e400f5d09e8ed6482c7c6e8af2db2 to your computer and use it in GitHub Desktop.
Save simonw/cd3e400f5d09e8ed6482c7c6e8af2db2 to your computer and use it in GitHub Desktop.

Fixing Safari Pomodoro Timer

human (Aug 28, 2024, 02:47 PM)

When I run this in Safari in a browser window that is out of focus the timer stops running down, fix it

assistant (Aug 28, 2024, 02:47 PM)

I understand you're having an issue with the Pomodoro Timer stopping when the Safari browser window is out of focus. This is a common problem with JavaScript timers in some browsers, including Safari. To fix this, we can use the Date object to calculate the time difference instead of relying on setInterval. This approach is more reliable across different browser states.

Let's modify the JavaScript part of the code to address this issue:

Pomodoro Timer with Safari Fix

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Pomodoro Timer</title>
    <style>
        body {
            font-family: Arial, sans-serif;
            display: flex;
            justify-content: center;
            align-items: center;
            height: 100vh;
            margin: 0;
            background-color: #f0f0f0;
        }
        .container {
            text-align: center;
            background-color: white;
            padding: 2rem;
            border-radius: 10px;
            box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
        }
        #timer {
            font-size: 4rem;
            margin-bottom: 1rem;
        }
        button, select {
            font-size: 1rem;
            padding: 0.5rem 1rem;
            margin: 0.5rem;
            border: none;
            border-radius: 5px;
            cursor: pointer;
            transition: background-color 0.3s;
        }
        #startBtn {
            background-color: #4CAF50;
            color: white;
        }
        #startBtn:hover {
            background-color: #45a049;
        }
        #resetBtn {
            background-color: #f44336;
            color: white;
        }
        #resetBtn:hover {
            background-color: #da190b;
        }
        select {
            background-color: #3498db;
            color: white;
        }
        select:hover {
            background-color: #2980b9;
        }
    </style>
</head>
<body>
    <div class="container">
        <h1>Pomodoro Timer</h1>
        <div id="timer">25:00</div>
        <select id="durationSelect">
            <option value="5">5 minutes</option>
            <option value="10">10 minutes</option>
            <option value="15">15 minutes</option>
            <option value="20">20 minutes</option>
            <option value="25" selected>25 minutes</option>
            <option value="30">30 minutes</option>
            <option value="45">45 minutes</option>
            <option value="60">60 minutes</option>
        </select>
        <br>
        <button id="startBtn">Start</button>
        <button id="resetBtn">Reset</button>
    </div>

    <script>
        const timerDisplay = document.getElementById('timer');
        const startBtn = document.getElementById('startBtn');
        const resetBtn = document.getElementById('resetBtn');
        const durationSelect = document.getElementById('durationSelect');

        let startTime;
        let timeLeft = 25 * 60; // Default to 25 minutes in seconds
        let isRunning = false;
        let duration = 25 * 60; // Default duration in seconds

        function updateDisplay() {
            const minutes = Math.floor(timeLeft / 60);
            const seconds = timeLeft % 60;
            timerDisplay.textContent = `${minutes.toString().padStart(2, '0')}:${seconds.toString().padStart(2, '0')}`;
        }

        function startTimer() {
            if (!isRunning) {
                isRunning = true;
                startBtn.textContent = 'Pause';
                durationSelect.disabled = true;
                startTime = Date.now() - ((duration - timeLeft) * 1000);
                requestAnimationFrame(updateTimer);
            } else {
                isRunning = false;
                startBtn.textContent = 'Resume';
            }
        }

        function updateTimer() {
            if (isRunning) {
                const elapsedTime = Math.floor((Date.now() - startTime) / 1000);
                timeLeft = duration - elapsedTime;

                if (timeLeft <= 0) {
                    timeLeft = 0;
                    isRunning = false;
                    startBtn.textContent = 'Start';
                    durationSelect.disabled = false;
                    alert('Pomodoro session complete!');
                } else {
                    requestAnimationFrame(updateTimer);
                }

                updateDisplay();
            }
        }

        function resetTimer() {
            isRunning = false;
            duration = parseInt(durationSelect.value) * 60;
            timeLeft = duration;
            updateDisplay();
            startBtn.textContent = 'Start';
            durationSelect.disabled = false;
        }

        function changeDuration() {
            if (!isRunning) {
                duration = parseInt(durationSelect.value) * 60;
                timeLeft = duration;
                updateDisplay();
            }
        }

        startBtn.addEventListener('click', startTimer);
        resetBtn.addEventListener('click', resetTimer);
        durationSelect.addEventListener('change', changeDuration);

        updateDisplay();
    </script>
</body>
</html>

I've made the following changes to fix the issue and improve the timer's accuracy:

  1. Replaced setInterval with requestAnimationFrame for smoother updates and better performance.
  2. Used the Date object to calculate elapsed time, which is more accurate and works even when the browser tab is not in focus.
  3. Introduced a startTime variable to keep track of when the timer started.
  4. Modified the updateTimer function to calculate the remaining time based on the elapsed time since the timer started.
  5. Updated the startTimer, resetTimer, and changeDuration functions to work with the new timing mechanism.

These changes should resolve the issue of the timer stopping when the Safari browser window is out of focus. The timer will now continue to run accurately in the background, even if the tab is not active.

To use this fixed version:

  1. Replace the entire content of your HTML file with the code provided in the artifact above.
  2. Save the file and reopen it in Safari.

The timer should now work correctly, even when the browser window is out of focus. Let me know if you have any questions or if you'd like any further modifications to the Pomodoro Timer!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment