I am trying to setup a communication channel between the service worker and the content script. I wanted to trigger a modal when the timer is up. I worked with two approaches.
First Approach:
Tried injecting the content script into target web page using the tabId. But the issue I faced with this approach was the user can close the popup and when the timer is again started then the modal will be shown the second time. Although it was shown properly for the first time but on the second time it threw error stating “cannot redeclare values”. I believe this is due to the fact that the content script was already injected for the first time and the second time it cannot redeclare the variables that were already present in the content script.
Second Approach:
Tried injecting the content script in every page and hide the modal initially. When the timer is up send a message from the service worker file to content script to show the popup and when the user click on restart timer then send a message back to service worker to reset and restart the timer. But here I am getting “Unchecked runtime.lastError: Could not establish connection. Receiving end does not exist.”
Kindly help me with the above two approaches. How can I implement them efficiently and properly. I am more inclined towards approach first as it doesn’t unnecessarily inject the content script into pages where it is not required.
Thanks
content-script.js
/**
* This script will handle showing a popup box when the
* timer for the website is complete informing user
* that they have reached their set time limit
*/
const timerPopupContainer = document.createElement("div");
timerPopupContainer.classList.add("popup-container");
timerPopupContainer.classList.add("hide-popup");
timerPopupContainer.innerHTML = `
<div class="popup">
<h2>Your set time limit for this website has been reached.</h2>
<p>You've spent plenty of time on this website. It's a good time to take a break!</p>
<br />
<p>Here are some suggestions:</p>
<ul>
<li>
Do some stretches: <a href="https://www.self.com/gallery/essential-stretches-slideshow">Simple Stretches</a>
</li>
<li>
Take a deep breath: <a href="https://www.youtube.com/watch?v=DbDoBzGY3vo">Guided Breathing Exercise</a>
</li>
<li>Check your to-do list for today's tasks.</li>
</ul>
<br />
<div class="mm-btn-group">
<button class="mm-btn">Start Over</button>
</div>
</div>`;
const resetBtn = timerPopupContainer.querySelector(
".mm-btn-group .mm-btn:last-child"
);
resetBtn.addEventListener("click", () => {
timerPopupContainer.classList.add("hide-popup");
});
document.body.appendChild(timerPopupContainer);
chrome.runtime.onMessage.addListener((message) => {
console.log(message, sender);
if (message.action === "show-popup")
timerPopupContainer.classList.remove("hide-popup");
});
service-worker.js
async function handleTrackedUrls() {
const trackedUrls = await getTrackedUrls();
const activeTimers = getRunningTrackedUrlTimers(trackedUrls);
for (const timer of activeTimers) {
if (timer.currTime === timer.defaultTime * 60) {
timer.currTime = 0;
timer.isRunning = false;
timer.isCompleted = true;
await clearAlarm(`${TRACKER_ALARM}_${timer.id}`);
await showNotification(timer.defaultTime);
await chrome.tabs.sendMessage(timer.tabId, { action: "show-popup" });
} else {
timer.currTime += 1;
const badgeText = generateBadgeText(timer.defaultTime, timer.currTime);
await chrome.action.setBadgeText({
text: `${badgeText}`,
tabId: timer.tabId,
});
}
}
await updateTrackedUrls(trackedUrls);
}