popup-timer/popup/script.js
2025-08-05 18:04:45 +02:00

301 lines
6.8 KiB
JavaScript

var params = parseQueryParams();
// Set window title
if (params.name) document.title = params.name + " - Popup Timer";
var hours, minutes, seconds;
var secondsElem = document.getElementById("seconds");
var minutesElem = document.getElementById("minutes");
var hoursElem = document.getElementById("hours");
var playBtn = document.getElementById("play");
var progressBar = document.getElementById("progress-fg");
var timeout;
var timesUpStr = "[ TIME'S UP! ] ";
var lastPaused = -1;
// Init audio
var oscillator, audioContext;
if (params.beep === "true") {
try {
audioContext = new (window.AudioContext || window.webkitAudioContext);
} catch(e) {}
}
// Initialize clock and start
switch (params.type) {
case "timer":
initTimer();
if (params.autostart === "true") startTimer(1000);
break;
case "stopwatch":
initStopwatch();
if (params.autostart === "true") startStopwatch(1000);
break;
default:
location.href = "/";
}
// Reset timer/stopwatch
document.getElementById("restart").onclick = function() {
if (timeout) clearTimeout(timeout);
var paused = playBtn.classList.contains("fa-play");
switch (params.type) {
case "timer":
// Reset progress bar
// TODO
progressBar.animationName = "";
progressBar.animationName = "progress";
initTimer();
if (!paused) startTimer(1000);
break;
case "stopwatch":
// Reset displayed time
secondsElem.innerText = "00s";
secondsElem.classList.remove("highlighted");
minutesElem.innerText = "00m";
minutesElem.classList.remove("highlighted");
hoursElem.innerText = "00h";
hoursElem.classList.remove("highlighted");
initStopwatch();
if (!paused) startStopwatch(1000);
break;
}
}
// Pause / Resume
playBtn.onclick = function() {
// Pause
if (playBtn.classList.contains("fa-pause")) {
lastPaused = Date.now();
if (params.type === "timer") progressBar.style.animationPlayState = "paused";
clearTimeout(timeout);
// Change icon
playBtn.classList.remove("fa-pause");
playBtn.classList.add("fa-play");
// Resume
} else {
var startOffset = lastPaused % 1000;
switch (params.type) {
case "timer":
if (hours === 0 && minutes == 0 && seconds === 0) return;
progressBar.style.animationPlayState = "running";
startTimer(startOffset);
break;
case "stopwatch":
startStopwatch(startOffset);
break;
}
// Change icon
playBtn.classList.remove("fa-play");
playBtn.classList.add("fa-pause");
}
}
function initTimer() {
hours = parseInt(params.h);
minutes = parseInt(params.m);
seconds = parseInt(params.s);
if (hours === 0 && minutes === 0 && seconds === 0) return;
// Only highlight relevant parts
if (hours > 0) {
hoursElem.classList.add("highlighted");
minutesElem.classList.add("highlighted");
secondsElem.classList.add("highlighted");
} else if (minutes > 0) {
minutesElem.classList.add("highlighted");
secondsElem.classList.add("highlighted");
} else {
secondsElem.classList.add("highlighted");
}
// Print initial time
hoursElem.innerText = pad(hours) + "h";
minutesElem.innerText = pad(minutes) + "m";
secondsElem.innerText = pad(seconds) + "s";
// Animate progress bar
var totalSeconds = (hours * 60 * 60) + (minutes * 60) + seconds;
progressBar.style.animationDuration = totalSeconds + "s";
progressBar.style.animationName = "progress";
}
function startTimer(startOffset) {
if (hours === 0 && minutes == 0 && seconds === 0) return;
playBtn.classList.remove("fa-play");
playBtn.classList.add("fa-pause");
// Wait the starting offset
timeout = setTimeout(updateTimer, startOffset);
document.getElementById("progress-fg").style.animationPlayState = "running";
}
function updateTimer() {
seconds--;
if (seconds === 0 && minutes === 0 && hours === 0) secondsElem.classList.remove("highlighted");
if (seconds <= -1) {
seconds = 59;
minutes--;
if (minutes === 0 && hours === 0) minutesElem.classList.remove("highlighted");
if (minutes <= -1) {
minutes = 59;
hours--;
if (hours === 0) hoursElem.classList.remove("highlighted");
hoursElem.innerText = pad(hours) + "h";
}
minutesElem.innerText = pad(minutes) + "m";
}
secondsElem.innerText = pad(seconds) + "s";
if (hours === 0 && minutes === 0 && seconds == 0) timeUp();
else timeout = setTimeout(updateTimer, 1000);
}
// Makes the numbers blink red etc.
function timeUp() {
var timeUpInterval = setInterval(function() {
// Blink red
[].slice.call(document.querySelectorAll("main > span")).forEach(function(elem) {
elem.classList.toggle("red");
});
//document.querySelector
// Blink title
if (document.title.indexOf(timesUpStr) === -1) document.title = timesUpStr + document.title;
else document.title = document.title.substr(timesUpStr.length);
// Play beep
if (params.beep === "true" && audioContext) {
try {
oscillator = audioContext.createOscillator();
oscillator.type = "sine";
oscillator.frequency.value = 1000;
oscillator.connect(audioContext.destination);
oscillator.start();
oscillator.stop(audioContext.currentTime + 0.25);
} catch(e) {}
}
}, 500);
// Stop when user clicks
document.onclick = function() {
if (oscillator) oscillator.stop();
// Reset color
[].slice.call(document.querySelectorAll("main > span")).forEach(function(elem) {
elem.classList.remove("red");
});
// Remove "TIME UP" from title
if (document.title.indexOf(timesUpStr) !== -1) document.title = document.title.substr(timesUpStr.length);
// Clean up
clearInterval(timeUpInterval);
document.onclick = null;
}
}
function initStopwatch() {
hours = 0;
minutes = 0;
seconds = 0;
}
function startStopwatch(startOffset) {
playBtn.classList.remove("fa-play");
playBtn.classList.add("fa-pause");
timeout = setTimeout(updateStopwatch, startOffset);
}
function updateStopwatch() {
// Update seconds
seconds++;
if (hours === 0 && minutes === 0 && seconds === 1) secondsElem.classList.add("highlighted");
if (seconds >= 60) {
seconds = 0;
// Update minutes
minutes++;
if (hours === 0 && minutes === 1) minutesElem.classList.add("highlighted");
if (minutes >= 60) {
minutes = 0;
// Update hours
hours++;
if (hours === 1) hoursElem.classList.add("highlighted");
hoursElem.innerText = pad(hours) + "h";
}
// Minutes
minutesElem.innerText = pad(minutes) + "m";
}
// Seconds
secondsElem.innerText = pad(seconds) + "s";
timeout = setTimeout(updateStopwatch, 1000);
}
function parseQueryParams() {
if (location.search === "" || location.search.indexOf("?") !== 0) return {};
var result = {};
location.search.substr(1).split("&").forEach(function(str) {
var key = str.split("=")[0];
var value;
if (str.split("=").length > 1) value = str.split("=")[1];
else value = null;
result[key] = value;
});
return result;
}
// Adds one leading zero if necessary
function pad(num) {
return ("00" + num).substr(-2);
}