JIT
creating a stopwatch application with interactive features
document.addEventListener('DOMContentLoaded', () => { const container = document.getElementById('stopwatch-container'); const addBoxBtn = document.getElementById('addBoxBtn'); let activeStopwatch = null; // The 'S' key will start or stop the active stopwatch document.addEventListener('keydown', (e) => { if (e.key === 's' || e.key === 'S') { if (activeStopwatch) { const startStopBtn = activeStopwatch.querySelector('.start-btn'); if (startStopBtn.textContent === 'Start') { startStopBtn.textContent = 'Stop'; startStopwatch(activeStopwatch); } else { startStopBtn.textContent = 'Start'; stopStopwatch(activeStopwatch); } } } }); // Add a new stopwatch box when the button is clicked addBoxBtn.addEventListener('click', () => { const newStopwatch = createStopwatchBox(); container.appendChild(newStopwatch); setActiveStopwatch(newStopwatch); }); // Handle clicks within the container to set the active stopwatch container.addEventListener('click', (e) => { const box = e.target.closest('.stopwatch-box'); if (box) { setActiveStopwatch(box); } }); // Function to set the active stopwatch box function setActiveStopwatch(box) { if (activeStopwatch) { activeStopwatch.classList.remove('active'); } activeStopwatch = box; activeStopwatch.classList.add('active'); } // Function to create a new stopwatch box element function createStopwatchBox() { const box = document.createElement('div'); box.classList.add('stopwatch-box'); box.innerHTML = ` <div class="timer-display">00:00:00</div> <div class="controls"> <button class="start-btn">Start</button> <button class="reset-btn">Reset</button> </div> <button class="remove-btn">&times;</button> `; const display = box.querySelector('.timer-display'); const startStopBtn = box.querySelector('.start-btn'); const resetBtn = box.querySelector('.reset-btn'); const removeBtn = box.querySelector('.remove-btn'); let timerInterval = null; let startTime = 0; let elapsedTime = 0; // Start/Stop button logic startStopBtn.addEventListener('click', () => { if (startStopBtn.textContent === 'Start') { startStopBtn.textContent = 'Stop'; startStopwatch(box); } else { startStopBtn.textContent = 'Start'; stopStopwatch(box); } }); // Reset button logic resetBtn.addEventListener('click', () => { stopStopwatch(box); elapsedTime = 0; display.textContent = formatTime(elapsedTime); startStopBtn.textContent = 'Start'; }); // Remove button logic removeBtn.addEventListener('click', (e) => { e.stopPropagation(); // Prevents clicking the box when removing stopStopwatch(box); box.remove(); if (activeStopwatch === box) { activeStopwatch = null; } }); // Function to start the stopwatch function startStopwatch(currentBox) { if (!timerInterval) { startTime = Date.now() - elapsedTime; timerInterval = setInterval(() => { elapsedTime = Date.now() - startTime; currentBox.querySelector('.timer-display').textContent = formatTime(elapsedTime); }, 100); // Update every 100ms } } // Function to stop the stopwatch function stopStopwatch(currentBox) { clearInterval(timerInterval); timerInterval = null; } // Function to format the time display function formatTime(ms) { const date = new Date(ms); const minutes = String(date.getUTCMinutes()).padStart(2, '0'); const seconds = String(date.getUTCSeconds()).padStart(2, '0'); const milliseconds = String(Math.floor(date.getUTCMilliseconds() / 100)).padStart(1, '0'); return `${minutes}:${seconds}:${milliseconds}`; } return box; } });
Updated files
v1
document.addEventListener('DOMContentLoaded', () => { const container = document.getElementById('stopwatch-container'); const addBoxBtn = document.getElementById('addBoxBtn'); let activeStopwatch = null; const allStopwatches = []; // The 'S' key will start or stop the active stopwatch document.addEventListener('keydown', (e) => { if (e.key === 's' || e.key === 'S') { if (activeStopwatch) { const startStopBtn = activeStopwatch.querySelector('.start-btn'); if (startStopBtn.textContent === 'Start') { startStopBtn.textContent = 'Stop'; startStopwatch(activeStopwatch); } else { startStopBtn.textContent = 'Start'; stopStopwatch(activeStopwatch); } } } }); // Add a new stopwatch box when the button is clicked addBoxBtn.addEventListener('click', () => { const newStopwatch = createStopwatchBox(); container.appendChild(newStopwatch); allStopwatches.push(newStopwatch); setActiveStopwatch(newStopwatch); }); // Handle clicks within the container to set the active stopwatch container.addEventListener('click', (e) => { const box = e.target.closest('.stopwatch-box'); if (box) { setActiveStopwatch(box); } }); // Function to set the active stopwatch box function setActiveStopwatch(box) { if (activeStopwatch) { activeStopwatch.classList.remove('active'); } activeStopwatch = box; activeStopwatch.classList.add('active'); box.querySelector('.stopwatch-name-input').focus(); } // Function to create a new stopwatch box element function createStopwatchBox() { const box = document.createElement('div'); box.classList.add('stopwatch-box'); box.innerHTML = ` <div class="stopwatch-box-header"> <input type="text" class="stopwatch-name-input" value="Stopwatch"> </div> <div class="timer-display">00:00:00</div> <div class="controls"> <button class="start-btn">Start</button> <button class="reset-btn">Reset</button> </div> <button class="remove-btn">&times;</button> `; const display = box.querySelector('.timer-display'); const startStopBtn = box.querySelector('.start-btn'); const resetBtn = box.querySelector('.reset-btn'); const removeBtn = box.querySelector('.remove-btn'); const nameInput = box.querySelector('.stopwatch-name-input'); let timerInterval = null; let startTime = 0; let elapsedTime = 0; box.elapsedTime = elapsedTime; // Store elapsedTime on the box element // Start/Stop button logic startStopBtn.addEventListener('click', () => { if (startStopBtn.textContent === 'Start') { startStopBtn.textContent = 'Stop'; startStopwatch(box); } else { startStopBtn.textContent = 'Start'; stopStopwatch(box); } }); // Reset button logic resetBtn.addEventListener('click', () => { stopStopwatch(box); elapsedTime = 0; box.elapsedTime = 0; // Reset stored time display.textContent = formatTime(elapsedTime); startStopBtn.textContent = 'Start'; sortStopwatches(); }); // Remove button logic removeBtn.addEventListener('click', (e) => { e.stopPropagation(); stopStopwatch(box); const index = allStopwatches.indexOf(box); if (index > -1) { allStopwatches.splice(index, 1); } box.remove(); if (activeStopwatch === box) { activeStopwatch = null; } sortStopwatches(); }); // Function to start the stopwatch function startStopwatch(currentBox) { if (!timerInterval) { startTime = Date.now() - elapsedTime; timerInterval = setInterval(() => { elapsedTime = Date.now() - startTime; currentBox.elapsedTime = elapsedTime; // Update stored time currentBox.querySelector('.timer-display').textContent = formatTime(elapsedTime); sortStopwatches(); }, 100); } } // Function to stop the stopwatch function stopStopwatch(currentBox) { clearInterval(timerInterval); timerInterval = null; } // Function to format the time display function formatTime(ms) { const date = new Date(ms); const minutes = String(date.getUTCMinutes()).padStart(2, '0'); const seconds = String(date.getUTCSeconds()).padStart(2, '0'); const milliseconds = String(Math.floor(date.getUTCMilliseconds() / 100)).padStart(1, '0'); return `${minutes}:${seconds}:${milliseconds}`; } return box; } // Function to sort stopwatches based on their elapsed time function sortStopwatches() { allStopwatches.sort((a, b) => b.elapsedTime - a.elapsedTime); allStopwatches.forEach(box => container.appendChild(box)); } });
Updated files
v2
document.addEventListener('DOMContentLoaded', () => { const container = document.getElementById('stopwatch-container'); const addBoxBtn = document.getElementById('addBoxBtn'); let activeStopwatch = null; const allStopwatches = []; // The main keydown event listener document.addEventListener('keydown', (e) => { // Find the active stopwatch and check its assigned key if (activeStopwatch) { const assignedKey = activeStopwatch.keybinding; if (e.key.toLowerCase() === assignedKey.toLowerCase()) { const startStopBtn = activeStopwatch.querySelector('.start-btn'); if (startStopBtn.textContent === 'Start') { startStopBtn.textContent = 'Stop'; startStopwatch(activeStopwatch); } else { startStopBtn.textContent = 'Start'; stopStopwatch(activeStopwatch); } } } }); // Add a new stopwatch box when the button is clicked addBoxBtn.addEventListener('click', () => { const newStopwatch = createStopwatchBox(); container.appendChild(newStopwatch); allStopwatches.push(newStopwatch); setActiveStopwatch(newStopwatch); }); // Handle clicks within the container to set the active stopwatch container.addEventListener('click', (e) => { const box = e.target.closest('.stopwatch-box'); if (box) { setActiveStopwatch(box); } }); // Function to set the active stopwatch box function setActiveStopwatch(box) { if (activeStopwatch) { activeStopwatch.classList.remove('active'); } activeStopwatch = box; activeStopwatch.classList.add('active'); box.querySelector('.stopwatch-name-input').focus(); } // Function to create a new stopwatch box element function createStopwatchBox() { const box = document.createElement('div'); box.classList.add('stopwatch-box'); box.innerHTML = ` <div class="stopwatch-box-header"> <input type="text" class="stopwatch-name-input" value="Stopwatch"> <input type="text" class="key-input" maxlength="1" value="S"> </div> <div class="timer-display">00:00:00</div> <div class="controls"> <button class="start-btn">Start</button> <button class="reset-btn">Reset</button> </div> <button class="remove-btn">&times;</button> `; const display = box.querySelector('.timer-display'); const startStopBtn = box.querySelector('.start-btn'); const resetBtn = box.querySelector('.reset-btn'); const removeBtn = box.querySelector('.remove-btn'); const nameInput = box.querySelector('.stopwatch-name-input'); const keyInput = box.querySelector('.key-input'); let timerInterval = null; let startTime = 0; let elapsedTime = 0; box.elapsedTime = elapsedTime; box.keybinding = keyInput.value.toLowerCase(); // Default keybinding // Update keybinding when input changes keyInput.addEventListener('input', () => { box.keybinding = keyInput.value.toLowerCase(); }); // Start/Stop button logic startStopBtn.addEventListener('click', () => { if (startStopBtn.textContent === 'Start') { startStopBtn.textContent = 'Stop'; startStopwatch(box); } else { startStopBtn.textContent = 'Start'; stopStopwatch(box); } }); // Reset button logic resetBtn.addEventListener('click', () => { stopStopwatch(box); elapsedTime = 0; box.elapsedTime = 0; display.textContent = formatTime(elapsedTime); startStopBtn.textContent = 'Start'; sortStopwatches(); }); // Remove button logic removeBtn.addEventListener('click', (e) => { e.stopPropagation(); stopStopwatch(box); const index = allStopwatches.indexOf(box); if (index > -1) { allStopwatches.splice(index, 1); } box.remove(); if (activeStopwatch === box) { activeStopwatch = null; } sortStopwatches(); }); // Function to start the stopwatch function startStopwatch(currentBox) { if (!timerInterval) { startTime = Date.now() - elapsedTime; timerInterval = setInterval(() => { elapsedTime = Date.now() - startTime; currentBox.elapsedTime = elapsedTime; currentBox.querySelector('.timer-display').textContent = formatTime(elapsedTime); sortStopwatches(); }, 100); } } // Function to stop the stopwatch function stopStopwatch(currentBox) { clearInterval(timerInterval); timerInterval = null; } // Function to format the time display function formatTime(ms) { const date = new Date(ms); const minutes = String(date.getUTCMinutes()).padStart(2, '0'); const seconds = String(date.getUTCSeconds()).padStart(2, '0'); const milliseconds = String(Math.floor(date.getUTCMilliseconds() / 100)).padStart(1, '0'); return `${minutes}:${seconds}:${milliseconds}`; } return box; } // Function to sort stopwatches based on their elapsed time function sortStopwatches() { allStopwatches.sort((a, b) => b.elapsedTime - a.elapsedTime); allStopwatches.forEach(box => container.appendChild(box)); } });
Updated files
v3
document.addEventListener('DOMContentLoaded', () => { const container = document.getElementById('stopwatch-container'); const addBoxBtn = document.getElementById('addBoxBtn'); let allStopwatches = []; const selectedStopwatches = new Set(); // The main keydown event listener document.addEventListener('keydown', (e) => { // Find the key for the first selected stopwatch to use as the group key if (selectedStopwatches.size > 0) { const firstSelected = selectedStopwatches.values().next().value; const assignedKey = firstSelected.keybinding; if (e.key.toLowerCase() === assignedKey.toLowerCase()) { const isRunning = firstSelected.classList.contains('running'); selectedStopwatches.forEach(box => { const startStopBtn = box.querySelector('.start-btn'); if (isRunning) { startStopBtn.textContent = 'Start'; stopStopwatch(box); } else { startStopBtn.textContent = 'Stop'; startStopwatch(box); } }); } } }); // Add a new stopwatch box addBoxBtn.addEventListener('click', () => { const newStopwatch = createStopwatchBox(); container.appendChild(newStopwatch); allStopwatches.push(newStopwatch); toggleSelection(newStopwatch); }); // Handle clicks within the container to select/deselect boxes container.addEventListener('click', (e) => { const box = e.target.closest('.stopwatch-box'); if (box) { toggleSelection(box); } }); // Function to toggle the selection of a stopwatch box function toggleSelection(box) { if (selectedStopwatches.has(box)) { selectedStopwatches.delete(box); box.classList.remove('active'); } else { selectedStopwatches.add(box); box.classList.add('active'); } } // Function to create a new stopwatch box element function createStopwatchBox() { const box = document.createElement('div'); box.classList.add('stopwatch-box'); box.innerHTML = ` <div class="stopwatch-box-header"> <input type="text" class="stopwatch-name-input" value="Stopwatch"> <input type="text" class="key-input" maxlength="1" value="S"> </div> <div class="timer-display">00:00:00</div> <div class="controls"> <button class="start-btn">Start</button> <button class="reset-btn">Reset</button> </div> <button class="remove-btn">&times;</button> `; const display = box.querySelector('.timer-display'); const startStopBtn = box.querySelector('.start-btn'); const resetBtn = box.querySelector('.reset-btn'); const removeBtn = box.querySelector('.remove-btn'); const nameInput = box.querySelector('.stopwatch-name-input'); const keyInput = box.querySelector('.key-input'); let timerInterval = null; let startTime = 0; let elapsedTime = 0; box.elapsedTime = elapsedTime; box.keybinding = keyInput.value.toLowerCase(); // Update keybinding when input changes keyInput.addEventListener('input', () => { box.keybinding = keyInput.value.toLowerCase(); }); // Start/Stop button logic startStopBtn.addEventListener('click', (e) => { e.stopPropagation(); // Prevents click from toggling selection if (startStopBtn.textContent === 'Start') { startStopBtn.textContent = 'Stop'; startStopwatch(box); } else { startStopBtn.textContent = 'Start'; stopStopwatch(box); } }); // Reset button logic resetBtn.addEventListener('click', (e) => { e.stopPropagation(); stopStopwatch(box); elapsedTime = 0; box.elapsedTime = 0; display.textContent = formatTime(elapsedTime); startStopBtn.textContent = 'Start'; box.classList.remove('running'); sortStopwatches(); }); // Remove button logic removeBtn.addEventListener('click', (e) => { e.stopPropagation(); stopStopwatch(box); const index = allStopwatches.indexOf(box); if (index > -1) { allStopwatches.splice(index, 1); } selectedStopwatches.delete(box); box.remove(); sortStopwatches(); }); // Function to start the stopwatch function startStopwatch(currentBox) { if (!currentBox.classList.contains('running')) { currentBox.classList.add('running'); startTime = Date.now() - currentBox.elapsedTime; currentBox.timerInterval = setInterval(() => { currentBox.elapsedTime = Date.now() - startTime; currentBox.querySelector('.timer-display').textContent = formatTime(currentBox.elapsedTime); sortStopwatches(); }, 100); } } // Function to stop the stopwatch function stopStopwatch(currentBox) { clearInterval(currentBox.timerInterval); currentBox.timerInterval = null; currentBox.classList.remove('running'); } // Function to format the time display function formatTime(ms) { const date = new Date(ms); const minutes = String(date.getUTCMinutes()).padStart(2, '0'); const seconds = String(date.getUTCSeconds()).padStart(2, '0'); const milliseconds = String(Math.floor(date.getUTCMilliseconds() / 100)).padStart(1, '0'); return `${minutes}:${seconds}:${milliseconds}`; } return box; } // Function to sort stopwatches based on their elapsed time function sortStopwatches() { allStopwatches.sort((a, b) => b.elapsedTime - a.elapsedTime); allStopwatches.forEach(box => container.appendChild(box)); } });
Updated files
v4
add another mode, with vertical stopwatch bars going up, with a color coded bar for each named bar with a higher number going over the other, with the timer going past 60.0
Write file
Added vertical bar mode with color-coded bars
v5
I meant, the boxes are thinner on the left side of the screen, adding more stopwatches on top of each other if needed, with the same mechanics, with the timer going past 60.0, not 1:00:0, and make this a different mode with a button, keeping the original stopwatch and the vertical side stopwatch
Read file

What do you mean by "higher number going over the other" for the vertical bars—do you want taller bars to visually overlap shorter ones (e.g., via absolute positioning and layering)? Also, should the stacked bars be in a narrow fixed container on the left with scroll if many, or overlap in place?

Write file
Implemented vertical bar mode with overlapping bars
v6
I ASKED FOR A SEPERATE MODE WITH A BUTTON TO ACCESS THAT MODE. WITH STOPWATCHES THIN, ON TOP OF EACH OTHER ON A VERTICAL LINE, THE BOXES ARE THINNER WITH THE TIMER GOING PAST 60.0, NOT 1:00.0. AND THE SECONDS THAT GO HIGHER CONTROL A COLOR CODED BAR THAT RISES.
Write file
Refined vertical bar mode with thin stacking bars
v7
what are you not getting? Where is the other mode?
Write file
Implemented separate vertical bar mode with independent container
v8