How to store data within a Google Chrome Extension? - javascript

I'm trying to make a google chrome extension, where there is a stopwatch where users can click start, stop or reset buttons. Upon clicking this stopwatch, I want the time to save within the extension itself so that users can always click out of the extension, but the time on the stopwatch will always keep going (until they press stop). I also want to constantly display the running time on the users screen, like this extension here:
[1]: https://i.stack.imgur.com/k0HMg.png
Here is my code:
//defining variables.
let seconds = 0;
let minutes = 0;
let hours = 0;
//these variables work to add a second "0" when there is only 1 digit in each respective value.
let displaySeconds = 0;
let displayMinutes = 0;
let displayHours = 0;
//this variable is used to work the setInterval() method.
let interval = null;
//this variable holds the stopwatch's status.
let status = "stopped";
//stopwatch function, determining when to increment next value, and when to bring current values to zero.
function stopWatch() {
seconds++;
if (seconds / 60 === 1) {
seconds = 0;
minutes++;
if (minutes / 60 === 1) {
minutes = 0;
hours++;
}
}
//if any of the values within the timer are only 1 digit in length, we will add ANOTHER zero to it.
if (seconds < 10) {
displaySeconds = "0" + seconds.toString();
} else {
displaySeconds = seconds;
}
if (minutes < 10) {
displayMinutes = "0" + minutes.toString();
} else {
displayMinutes = minutes;
}
if (hours < 10) {
displayHours = "0" + hours.toString();
} else {
displayHours = hours;
}
//this part of the function will update the display every 1 second.
document.getElementById("stopwatch-face").innerHTML = displayHours + ":" + displayMinutes + ":" + displaySeconds;
}
function startStop() {
if (status === "stopped") {
interval = window.setInterval(stopWatch, 1000); //this plays out a certain function every set amount of time
document.getElementById("startStop").innerHTML = "Stop";
status = "start";
} else {
window.clearInterval(interval);
document.getElementById("startStop").innerHTML = "Start";
status = "stopped";
}
}
//this function will reset the stopwatch.
function reset() {
window.clearInterval(interval);
seconds = 0;
minutes = 0;
hours = 0;
document.getElementById("stopwatch-face").innerHTML = "00:00:00";
document.getElementById("startStop").innerHTML = "Start";
}
//This is what you do instead of "onclick", to make extensions....:
document.addEventListener('DOMContentLoaded', function() {
document.getElementById("startStop").addEventListener("click", startStop);
});
document.addEventListener('DOMContentLoaded', function() {
document.getElementById("reset").addEventListener("click", reset);
});
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<title>Snap Focus</title>
<link rel="preconnect" href="https://fonts.gstatic.com">
<link href="https://fonts.googleapis.com/css2?family=Oswald:wght#200;300;400;500;600;700&display=swap" rel="stylesheet">
<link href="https://fonts.googleapis.com/css2?family=Poppins:ital,wght#0,300;0,400;1,300&display=swap" rel="stylesheet">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/#fortawesome/fontawesome-free#5.15.3/css/fontawesome.min.css" integrity="sha384-wESLQ85D6gbsF459vf1CiZ2+rr+CsxRY0RpiF1tLlQpDnAgg6rwdsUF1+Ics2bni" crossorigin="anonymous">
<script type="text/javascript" src="popup.js"></script>
<link rel="stylesheet" type="text/css" href="style.css">
</head>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css">
<div class="body">
<body>
<div class="content">
<div class="modal-header">
<div class="header">
<h1 className="Title"><strong>Snap Focus</strong></h1>
</div>
<div class="modal-subheader">
<p><i>Just press start to block unnecessary websites, and be more productive!</i></p>
</div>
<hr>
</div>
<div id="stopwatch-face">
00:00:00
</div>
<div class="buttons">
<button id="startStop">Start</button>
<button id="reset">Reset</button>
</div>
<br>
</div>
</body>
</div>
</html>
Any help is greatly appreciated!

Hi here's a small script I call to save data in an extension, hopefully you can use it. You'll probably need to add permission in your manifest, here's the chrome documentation
// Manage access_token storage
const TOKEN_NAME = 'faunaToken';
export function setAuth(token) {
chrome.storage.sync.set({ [TOKEN_NAME]: token });
}
export function removeAuth() {
chrome.storage.sync.remove([TOKEN_NAME]);
}
export function getAuth() {
return new Promise((resolve) => {
chrome.storage.sync.get([TOKEN_NAME], async (token) => {
resolve(token[TOKEN_NAME]);
});
});
}
and then use it like
import { setAuth } from '../scripts/AuthToken';
somePromise.then(data => setAuth(data.token));
By the way you probably don't want to call this every second to update the counter. It would probably be better to on click save the timestamp to storage and have popup.js determine time since the timestamp

Related

How to toggle a button with Javascript

I want to create a phone-like stopwatch using HTML, CSS, and vanilla JavaScript. The one I have already done does the task, but I don't want a separate button for stopping and starting. How could I make a button that changes from start to stop and stop to start?
Here is my HTML Code:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<div class="wrapper">
<h1>Stopwatch</h1>
<h2>Vanilla JavaScript Stopwatch</h2>
<p><span id="seconds">00</span>:<span id="tens">00</span></p>
<button id="button-start">Start</button>
<button id="button-stop">Stop</button>
<button id="button-reset">Reset</button>
</div>
</body>
</html>
Here is my JavaScript code:
window.onload = function () {
var seconds = 00;
var tens = 00;
var appendTens = document.getElementById("tens")
var appendSeconds = document.getElementById("seconds")
var buttonStart = document.getElementById('button-start');
var buttonStop = document.getElementById('button-stop');
var buttonReset = document.getElementById('button-reset');
var Interval ;
buttonStart.onclick = function() {
clearInterval(Interval);
Interval = setInterval(startTimer, 10);
}
buttonStop.onclick = function() {
clearInterval(Interval);
}
buttonReset.onclick = function() {
clearInterval(Interval);
tens = "00";
seconds = "00";
appendTens.innerHTML = tens;
appendSeconds.innerHTML = seconds;
}
function startTimer () {
tens++;
if(tens <= 9){
appendTens.innerHTML = "0" + tens;
}
if (tens > 9){
appendTens.innerHTML = tens;
}
if (tens > 99) {
console.log("seconds");
seconds++;
appendSeconds.innerHTML = "0" + seconds;
tens = 0;
appendTens.innerHTML = "0" + 0;
}
if (seconds > 9){
appendSeconds.innerHTML = seconds;
}
}
}
Define a boolean to track if the clock is running or not and combine the start and stop function into one: something like this:
var clockStarted = false;
buttonStart.onclick = function() {
clearInterval(Interval);
if (!clockStarted) {
Interval = setInterval(startTimer, 10);
clockStarted = true;
} else {
clockStarted = false;
}
}
buttonReset.onclick = function() {
clearInterval(Interval);
tens = "00";
seconds = "00";
appendTens.innerHTML = tens;
appendSeconds.innerHTML = seconds;
clockStarted = false;
}
You could make your play-button invisible after clicking on it (buttonStart.style.dispaly = "none") and enable your stop-button (buttonStop.style.dispaly = "block") and do the same in reverse in your stop function.
Another possible way would be to use only one button and save the state of your player in a variable (i.e. a boolen isPlaying). Then you'd only need one onPress method which starts or stops the player according to isPlaying. Youd also need to change the element or the icon on you button accoring to this variable.

Transforming minutes to ms giving unexpected result

Im developing a chess clock. The thing is that when Im retrieving the minutes and seconds from the DOM and transforming it with msToClockFormat I'm getting 100 times extra minutes. However, For more I look at the function, the more convinced I am that is working as it should be. The minutes are being divided by 60000, 1000 times 60`, and I dont see the error. Thanks.
let btn1 = document.getElementById("btn1");
let btn2 = document.getElementById("btn2");
let resetBtn = document.getElementById("reset");
let ms1 = stringTimeToMs(btn1.innerHTML);
let ms2 = stringTimeToMs(btn2.innerHTML);
let player1 = true;
let reset = false;
function tick() {
if (!reset) {
if (player1) {
btn1.innerHTML = msToClockFormat(--ms1);
} else {
btn2.innerHTML = msToClockFormat(--ms2);
}
}
}
function msToClockFormat(ms) {
let minutes = Math.floor(ms / 60000);
let seconds = Math.floor((ms % 60000) / 1000);
return minutes + ":" + (seconds < 10 ? "0" + seconds : seconds);
}
function stringTimeToMs(time) {
let minutes = time.split(":")[0];
let seconds = time.split(":")[1];
return (minutes * 60 + seconds) * 1000;
}
var myInterval = setInterval(tick, 1);
btn1.addEventListener("click", () => {
player1 = false;
reset = false;
})
btn2.addEventListener("click", () => {
player1 = true;
reset = false;
})
resetBtn.addEventListener("click", () => {
btn1.innerHTML = "05:00";
btn2.innerHTML = "05:00";
player1 = true;
ms1 = 5 * 60 * 1000;
ms2 = 5 * 60 * 1000;
reset = true;
})
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Clock</title>
<link rel="stylesheet" href="https://unpkg.com/#picocss/pico#latest/css/pico.min.css">
<script src="script.js" defer></script>
</head>
<body>
<main class="container">
<div class="container1">
<button class="timers" id="btn1">3:00</button>
</div>
<div class="container2">
<button class="timers" id="btn2">3:00</button>
</div>
<div class="container3">
<button id="reset">RESET</button>
</div>
</main>
</body>
</html>
You'd probably have a better time keeping your state in your code, and just writing it into the DOM elements.
I changed the tick interval to 1000ms (because it's unlikely setInterval would work correctly with 1ms), but even so it's not guaranteed that your function will be called exactly 1000ms apart, so it would be better to look at the wall clock (+new Date()) to see how much time actually elapsed since the last "tick".
let btn1 = document.getElementById("btn1");
let btn2 = document.getElementById("btn2");
let resetBtn = document.getElementById("reset");
let ms1 = 300000;
let ms2 = 300000;
let player1 = true;
let reset = false;
function update() {
btn1.innerHTML = msToClockFormat(ms1);
btn2.innerHTML = msToClockFormat(ms2);
}
function tick() {
if (!reset) {
if (player1) {
ms1 -= 1000;
} else {
ms2 -= 1000;
}
}
update();
}
function msToClockFormat(ms) {
let minutes = Math.floor(ms / 60000);
let seconds = Math.floor((ms % 60000) / 1000);
return minutes + ":" + (seconds < 10 ? "0" + seconds : seconds);
}
update();
var myInterval = setInterval(tick, 1000);
btn1.addEventListener("click", () => {
player1 = false;
reset = false;
})
btn2.addEventListener("click", () => {
player1 = true;
reset = false;
})
resetBtn.addEventListener("click", () => {
player1 = true;
ms1 = 5 * 60 * 1000;
ms2 = 5 * 60 * 1000;
reset = true;
})
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Clock</title>
<link rel="stylesheet" href="https://unpkg.com/#picocss/pico#latest/css/pico.min.css">
<script src="script.js" defer></script>
</head>
<body>
<main class="container">
<div class="container1">
<button class="timers" id="btn1"></button>
</div>
<div class="container2">
<button class="timers" id="btn2"></button>
</div>
<div class="container3">
<button id="reset">RESET</button>
</div>
</main>
</body>
</html>
Inside StringTimeToMs, seconds is being read as String input "00" as opposed to integer. As a result, adding seconds in return (minutes * 60 + seconds) * 1000; is concatenating "00" to the end of the number, making the number larger. Use parseInt to read the integer value.
function stringTimeToMs(time) {
let minutes = time.split(":")[0];
let seconds = parseInt(time.split(":")[1]);
return (minutes * 60 + seconds) * 1000;
}

Is There A Wait Function In JavaScript? [duplicate]

This question already has answers here:
What is the JavaScript version of sleep()?
(91 answers)
Closed 1 year ago.
I Would Like To Create A Wait Between Each document.getElementById(), The Goal Of The Web App Is When You Load It, It Will Begin The Timer At 5, Every Second It Will Go Down And At The End Display The Message Completed, I Can Not Find The Right Function To Do This, I Am Fairly New To JavaScript, So This Is Probably A Stupid Question To You,
My JavaScript Code
window.onload = function timer(){
document.getElementById("timer").innerHTML = "Timer - 5";
document.getElementById("timer").innerHTML = "Timer - 4";
document.getElementById("timer").innerHTML = "Timer - 3";
document.getElementById("timer").innerHTML = "Timer - 2";
document.getElementById("timer").innerHTML = "Timer - 1";
document.getElementById("timer").innerHTML = "Timer - Completed";
}
My HTML Code
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Timer - Test</title>
<link rel="shortcut icon" href="Resources/favicon.ico" type="image/x-icon">
<link rel="stylesheet" href="./index.css">
<script src="./index.js"></script>
</head>
<body>
<div id="timer">
Welcome
</div>
</body>
</html>
Use setInterval():
window.onload = function timer() {
var time = 5;
var t = setInterval(() => {
if (time == -1) {
clearInterval(t);
return;
} else if (time == 0) {
document.getElementById("timer").innerHTML = "Timer - Completed";
return;
}
document.getElementById("timer").innerHTML = "Timer - " + time;
time--;
}, 1000);
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Timer - Test</title>
<link rel="shortcut icon" href="Resources/favicon.ico" type="image/x-icon">
<link rel="stylesheet" href="./index.css">
<script src="./index.js"></script>
</head>
<body>
<div id="timer">
Welcome
</div>
</body>
</html>
setTimeout and setInterval are what can help you here.
For example:
window.onload = function timer(){
document.getElementById("timer").innerHTML = "Timer - 5";
setTimeout(() => document.getElementById("timer").innerHTML = "Timer - 4", 1000);
setTimeout(() => document.getElementById("timer").innerHTML = "Timer - 3", 2000);
setTimeout(() => document.getElementById("timer").innerHTML = "Timer - 2", 3000);
setTimeout(() => document.getElementById("timer").innerHTML = "Timer - 1", 4000);
setTimeout(() => document.getElementById("timer").innerHTML = "Timer - DONE", 5000);
}
<div id="timer"></div>
There are other ways to implement this and improve the code, but this is the closest to the code you posted, so it should be easy to understand.
You can use the setTimeout() method in JavaScript. It allows you to delay a function for a set amount of time. Using recursion, you can create a function that calls itself, like this:
window.onload = () => {
const timer = document.getElementById("timer");
const countdown = (time) => {
// if time is up, return out of timer
if (time === 0) {
timer.innerHTML = "Timer - Completed";
return;
}
// set timer value to the current time
timer.innerHTML = `Timer - ${time}`;
// call the function with a timeout of 1 second (1000 milliseconds)
setTimeout(() => countdown(time - 1), 1000);
}
countdown(5);
}
Let me know if you have any questions!
setInterval is something you are looking for:
let timerId = null // it's id of our interval, we declaring it globally. Thanks to this we clear it (stop counting) when we need.
const startTimer = () => {
let counter = 5
timerId = setInterval(() => {
document.getElementById("timer").innerHTML =
--counter ? `Timer ${counter}` : "Timer - Completed"
if (counter === 0) clearInterval(timerId)
}, 1000) // time in ms
}
window.onload = function timer(){
startTimer() // we are starting our timer
}
window.destroy = function timer(){
clearInterval(timerId) // this is important! You don't want to leave runnig interval while you will change page before it ends.
}
<div id="timer">Welcome</div>
My favourite pattern is a recursive setTimeout.
function countdown() {
// Cache the element
const timer = document.getElementById("timer");
// Initialise count
function loop(count = 5) {
// If count is 0 print the completed message
if (!count) {
timer.textContent = 'Timer - Completed';
// Otherwise print the count and call the loop
// again with a reduced count that gets passed
// in as an argument
} else {
timer.textContent = `Timer - ${count}`;
setTimeout(loop, 1000, --count);
}
}
loop();
}
countdown();
<div id="timer" />

Javascript Start/Stop button changes innerHTML and starts timer but doesn't fulfil any of the other part of function

I have a button which I am trying to use as a start and stop for an event which starts or stops a countdown timer. However it currently only starts and changes to the stop but will not change back to start or stop the timer from counting down.
Is there a better way of doing this? I've also included the reset button as I've tried to reset things when it it's pushed but it currently just changes back to the start, but the start won't fire again after I have done this.
((d) => {
let btn = d.getElementById("btn");
let reset = d.getElementById("reset");
let countdown = d.getElementById("countdown");
let counter;
let startTime = 1500;
let timerFormat = (s) => {
return (s - (s %= 60)) / 60 + (9 < s ? ":" : ":0") + s;
};
countdown.innerHTML = timerFormat(startTime);
let timer = () => {
startTime--;
countdown.innerHTML = timerFormat(startTime);
if (startTime === 0) clearInterval(counter);
};
btn.addEventListener("click", () => {
if (stop) {
start();
btn.innerHTML = "Stop";
} else {
stop();
btn.innerHTML = "Start";
}
});
let start = () => {
counter = counter || setInterval(timer, 1000);
};
let stop = () => {
clearInterval(counter);
counter = undefined;
};
reset.onclick = () => {
startTime = 1500;
countdown.innerHTML = timerFormat(startTime);
if (btn.innerHTML === "Stop") {
btn.innerHTML = "Start";
}
};
})(document);
<!DOCTYPE html>
<html lang="en">
<head>
<title>Document</title>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<link rel="stylesheet" href="../styles/styles.css" />
<script defer src="../JS/timer.js"></script>
</head>
<body>
<div id="countdown"></div>
<div class="btn__container">
<button class="btn" id="btn">Start</button>
<button class="btn" id="reset">Reset</button>
</div>
</body>
</html>
Your problem is in how you are determining whether to start or stop:
if (stop) {
stop is a function, so it has a "truthy" value and your if statement will always evaluate to true. Instead, check the existence of counter.
Other:
Don't use .innerHTML if you can help it and certainly not when the
string you are working with doesn't contain any HTML. .innerHTML
has security and performance implications. Instead, use
.textContent.
While a timer isn't going to be 100% accurate for timekeeping, you
can make the counter a little bit more accurate by having the
callback run just a little under every second. The reason being that
running every second means you run the risk of possibly skipping over
a second on the counter if the timer doesn't run exactly one second
later.
((d) => {
let btn = d.getElementById("btn");
let reset = d.getElementById("reset");
let countdown = d.getElementById("countdown");
let counter;
let startTime = 1500;
let timerFormat = (s) => {
return (s - (s %= 60)) / 60 + (9 < s ? ":" : ":0") + s;
};
countdown.textContent = timerFormat(startTime);
let timer = () => {
startTime--;
countdown.textContent = timerFormat(startTime);
if (startTime === 0) clearInterval(counter);
};
btn.addEventListener("click", () => {
if (counter) {
stop();
btn.textContent = "Start";
} else {
start();
btn.textContent = "Stop";
}
});
let start = () => {
counter = counter || setInterval(timer, 950);
};
let stop = () => {
clearInterval(counter);
counter = null;
};
reset.onclick = () => {
startTime = 1500;
countdown.textContent = timerFormat(startTime);
if (btn.textContent === "Stop") {
btn.textContent = "Start";
}
};
})(document);
<!DOCTYPE html>
<html lang="en">
<head>
<title>Document</title>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<link rel="stylesheet" href="../styles/styles.css" />
<script defer src="../JS/timer.js"></script>
</head>
<body>
<div id="countdown"></div>
<div class="btn__container">
<button class="btn" id="btn">Start</button>
<button class="btn" id="reset">Reset</button>
</div>
</body>
</html>

Js how to add time counter onclick event

I'm using a custom video player with html5. I already got the video length contained in custom fields, so it's easy for me to stamp the duration on the player screen.
I just need now to stamp a 00:00:00 (which stands for seconds, minutes and hours) which will start a progressive count as soon as I press play in the video player.
I suppose I should put the command within this line of code:
playButton.addEventListener("click", function(){
if(video.paused==true){
video.play();
}
}
...and then create another script which makes the 00:00:00 be influenced by the addEventListener, but I don't have enough knowledge to create it properly.
Can you kindly help me doing it?
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>test</title>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js"></script>
</head>
<body>
<div>Time <span id="time">00:00:00</span> </div>
<div><button id="btn">pause</button></div>
<script>
var btn = document.getElementById("btn");
var btnFlag = false;
var timer = 1; // this is global variale
// flag means here play and pause 1 for play 0 for pause
function startTimer(duration, display) {
var mytimer = setInterval(function () {
if (++timer == duration ) {
timer--;
clearInterval(mytimer)
}
$("#btn").off('click').on('click',function(e){
//btn.addEventListener("click",function(e) {
console.log("click")
if(!btnFlag){
console.log("here")
btnFlag = true
clearInterval(mytimer)
$("#btn").text('Play')
}
else{
console.log("pass")
btnFlag = false
startTimer(duration, display)
$("#btn").text('Pause')
}
})
hours = parseInt(timer /3600, 10)
minutes = parseInt((timer % 3600) / 60, 10)
seconds = parseInt(timer % 60, 10);
hours = hours < 10 ? "0" + hours : hours;
minutes = minutes < 10 ? "0" + minutes : minutes;
seconds = seconds < 10 ? "0" + seconds : seconds;
display.textContent = hours + ":"+ minutes + ":" + seconds;
}, 1000);
}
window.onload = function () {
var timeinsecond = 100,
display = document.querySelector('#time');
startTimer(timeinsecond, display);
};
</script>
</body>
</html>
Try It

Categories