Skip to content

Commit

Permalink
feat: Edit each entry's start and end time
Browse files Browse the repository at this point in the history
  • Loading branch information
JeremieLitzler committed Aug 5, 2024
1 parent 606db43 commit 5740ed6
Show file tree
Hide file tree
Showing 8 changed files with 363 additions and 151 deletions.
18 changes: 15 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,12 +22,24 @@ It allowed time ranges applying to all blocked websites.

## Features ✅

A blocking entry is defined with:

- a URL chunk (ex: "youtube" or even "youtube.com")
- a start time (hour:minute)
- an end time (hour:minute)

You can have several entries with the same URL chunk but different time ranges.

You can :

- [x] Add as many websites as possible
- [x] Allow to remove a single entry
- [x] Add as many time ranges as possible per website
- [x] Enable autocomplete when typing website value
- [x] Make the blocked page dynamic (background changes)
- [ ] Enable edition of an entry
- [x] Block any website browsed to in the current hour and minute falls between any of the entries
- [x] Use the autocomplete when typing url chunck value
- [x] See the blocked page with a random background changes pulled [from Lorem Picsum](https://picsum.photos/).
- [x] Store entries in indexedDb
- [x] Edit each entry's start and end time
- [ ] Add tests
- [ ] Export and import configuration from a CSV file
- [ ] Export and import configuration from a JSON file
Expand Down
45 changes: 43 additions & 2 deletions background.js
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,34 @@ async function removeBlockedSite(id) {
});
}

async function updateBlockedSite(id, startTime, endTime) {
const db = await getDB();
return new Promise((resolve, reject) => {
const transaction = db.transaction(['blockedSites'], 'readwrite');
const objectStore = transaction.objectStore('blockedSites');
const getRequest = objectStore.get(id);

getRequest.onsuccess = function (event) {
const data = event.target.result;
data.startTime = startTime;
data.endTime = endTime;
const updateRequest = objectStore.put(data);

updateRequest.onsuccess = function () {
resolve();
};

updateRequest.onerror = function (event) {
reject('Error updating site: ' + event.target.error);
};
};

getRequest.onerror = function (event) {
reject('Error getting site for update: ' + event.target.error);
};
});
}

async function getAllBlockedSites() {
const db = await getDB();
return new Promise((resolve, reject) => {
Expand All @@ -83,6 +111,13 @@ async function getAllBlockedSites() {
}

chrome.runtime.onMessage.addListener((request, sender, sendResponse) => {
if (request.action === 'isDbReady') {
getDB()
.then(() => sendResponse({ dbReady: true }))
.catch(() => sendResponse({ dbReady: false }));
return true;
}

if (request.action === 'addSite') {
addBlockedSite(request.site, request.startTime, request.endTime)
.then(() => getAllBlockedSites())
Expand All @@ -95,6 +130,12 @@ chrome.runtime.onMessage.addListener((request, sender, sendResponse) => {
.then((sites) => sendResponse({ blockedSites: sites }))
.catch((error) => sendResponse({ error: error.toString() }));
return true;
} else if (request.action === 'updateSite') {
updateBlockedSite(request.id, request.startTime, request.endTime)
.then(() => getAllBlockedSites())
.then((sites) => sendResponse({ blockedSites: sites }))
.catch((error) => sendResponse({ error: error.toString() }));
return true;
} else if (request.action === 'getSites') {
getAllBlockedSites()
.then((sites) => sendResponse({ blockedSites: sites }))
Expand Down Expand Up @@ -133,8 +174,8 @@ function timeToMinutes(time) {

function isTimeInRange(current, start, end) {
if (start <= end) {
return current >= start && current <= end;
return current >= start && current < end;
} else {
return current >= start || current <= end;
return current >= start || current < end;
}
}
4 changes: 2 additions & 2 deletions manifest.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"manifest_version": 3,
"name": "Website Blocker",
"version": "0.0.0.27",
"version": "0.0.0.40",
"description": "Blocks specified websites during set times",
"permissions": ["storage", "tabs", "webNavigation"],
"host_permissions": ["<all_urls>"],
Expand All @@ -23,7 +23,7 @@
},
"web_accessible_resources": [
{
"resources": ["blocked.html", "blocked.js"],
"resources": ["blocked.html", "blocked.js", "manage.html", "manage.js"],
"matches": ["<all_urls>"]
}
],
Expand Down
54 changes: 7 additions & 47 deletions popup.html
Original file line number Diff line number Diff line change
Expand Up @@ -2,54 +2,14 @@
<html>
<head>
<title>Website Blocker</title>
<style>
body {
width: 300px;
padding: 10px;
font-family: Arial, sans-serif;
}
input {
width: 100%;
margin-bottom: 10px;
}
ul {
list-style-type: none;
padding: 0;
}
li {
margin-bottom: 15px;
border-bottom: 1px solid #ccc;
padding-bottom: 10px;
}
.time-inputs {
display: flex;
justify-content: space-between;
margin-top: 5px;
}
.time-inputs input {
width: 45%;
}
button {
margin-top: 5px;
}
</style>
</head>
<body>
<h2>Website Blocker</h2>
<input
type="text"
id="siteInput"
list="sitesList"
placeholder="Enter website to block (e.g., example.com)"
/>
<datalist id="sitesList"></datalist>
<div class="time-inputs">
<input type="time" id="startTime" value="00:00" />
<input type="time" id="endTime" value="23:59" />
</div>
<button id="addSite">Add Site</button>
<h3>Blocked Sites:</h3>
<ul id="blockedSitesList"></ul>
<body class="p-4">
<button
id="openManager"
class="bg-blue-500 text-white px-4 py-2 rounded-md hover:bg-blue-600"
>
Open Manager
</button>
<script src="popup.js"></script>
</body>
</html>
99 changes: 2 additions & 97 deletions popup.js
Original file line number Diff line number Diff line change
@@ -1,98 +1,3 @@
let blockedSites = [];

document.addEventListener('DOMContentLoaded', function () {
chrome.runtime.sendMessage({ action: 'getSites' }, function (response) {
if (chrome.runtime.lastError) {
console.error(chrome.runtime.lastError);
return;
}
if (response && response.blockedSites) {
blockedSites = response.blockedSites;
updateBlockedSitesList(blockedSites);
updateAutocompleteList();
}
});
document.getElementById('openManager').addEventListener('click', function () {
chrome.tabs.create({ url: 'settings.html' });
});

function updateAutocompleteList() {
const sitesList = document.getElementById('sitesList');
const uniqueSites = [...new Set(blockedSites.map((site) => site.site))];

sitesList.innerHTML = '';
uniqueSites.forEach((site) => {
const option = document.createElement('option');
option.value = site;
sitesList.appendChild(option);
});
}

document.getElementById('addSite').addEventListener('click', function () {
let siteInput = document.getElementById('siteInput');
let startTimeInput = document.getElementById('startTime');
let endTimeInput = document.getElementById('endTime');

let site = siteInput.value.trim();
let startTime = startTimeInput.value;
let endTime = endTimeInput.value;

if (site && startTime && endTime) {
chrome.runtime.sendMessage(
{
action: 'addSite',
site: site,
startTime: startTime,
endTime: endTime,
},
function (response) {
if (chrome.runtime.lastError) {
console.error(chrome.runtime.lastError);
return;
}
if (response && response.blockedSites) {
blockedSites = response.blockedSites;
siteInput.value = '';
startTimeInput.value = '00:00';
endTimeInput.value = '23:59';
updateBlockedSitesList(blockedSites);
updateAutocompleteList();
} else {
console.error('Invalid response from background script');
}
}
);
}
});

function updateBlockedSitesList(sites) {
let list = document.getElementById('blockedSitesList');
list.innerHTML = '';
sites.forEach(function (siteObj) {
let li = document.createElement('li');
li.textContent = `${siteObj.site} (${siteObj.startTime} - ${siteObj.endTime})`;
let removeButton = document.createElement('button');
removeButton.textContent = 'Remove';
removeButton.onclick = function () {
chrome.runtime.sendMessage(
{
action: 'removeSite',
id: siteObj.id,
},
function (response) {
if (chrome.runtime.lastError) {
console.error(chrome.runtime.lastError);
return;
}
if (response && response.blockedSites) {
blockedSites = response.blockedSites;
updateBlockedSitesList(blockedSites);
updateAutocompleteList();
} else {
console.error('Invalid response from background script');
}
}
);
};
li.appendChild(removeButton);
list.appendChild(li);
});
}
50 changes: 50 additions & 0 deletions settings.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Website Blocker Manager</title>
<script src="tailwind.js"></script>
</head>
<body class="bg-gray-100 min-h-screen">
<div class="container mx-auto p-8">
<h1 class="text-3xl font-bold mb-8">Website Blocker Manager</h1>
<div class="bg-white rounded-xl shadow-md p-6 mb-8">
<h2 class="text-2xl font-semibold mb-4">Add New Site</h2>
<div class="mb-4">
<input
type="text"
id="siteInput"
list="sitesList"
placeholder="Enter website to block"
class="w-full px-3 py-2 border rounded-md"
/>
<datalist id="sitesList"></datalist>
</div>
<div class="flex space-x-4 mb-4">
<input
type="time"
id="startTime"
class="flex-1 px-3 py-2 border rounded-md"
/>
<input
type="time"
id="endTime"
class="flex-1 px-3 py-2 border rounded-md"
/>
</div>
<button
id="addSite"
class="w-full bg-blue-500 text-white px-4 py-2 rounded-md hover:bg-blue-600"
>
Add Site
</button>
</div>
<div>
<h2 class="text-2xl font-semibold mb-4">Blocked Sites</h2>
<ul id="blockedSitesList" class="space-y-4"></ul>
</div>
</div>
<script src="settings.js"></script>
</body>
</html>
Loading

0 comments on commit 5740ed6

Please sign in to comment.