- 5
- 0
- 0
How to create your own Chrome extension that removes clutter from websites
We think almost everyone has found themselves in a passive battle against website clutter – one in which the user never quite achieves the desired victory.
As you can imagine, we’re talking about the countless ads on websites that often get in the way of viewing content, pop-ups, and the like. Some people don’t care about this, while for others it’s a total nightmare.
Well, thank goodness for technology that lets us solve this problem and eliminate the annoyances of browsing websites. In this article, we’ll walk through how to create an extension that removes clutter and lets you enjoy a comfortable browsing experience.
Let’s dive in!
A bit about the extension’s structure
Our extension will consist of:
- manifest.json – a file that tells the browser this is an extension.
- content.js – a file containing the extension’s core logic.
- background.js – the logic for the context menu.
- popup.html – a menu for enabling and disabling the extension on websites.
- popup.js – the logic for the popup menu.
How do you create this extension?
First, create a folder with any name, and then create the 5 files mentioned above (manifest.json, content.js, background.js, popup.html, popup.js) inside it.
Next, follow these steps:
- Open manifest.json and paste the following into it:
{
“manifest_version”:3,
“name”:”Element Cleaner Per Site”,
“version”:”2.0.0″,
“description”:”Deleting page elements through the context menu with inclusion on individual sites.”,
“permissions”:[
“contextMenus”,
“tabs”,
“storage”,
“activeTab”
],
“host_permissions”:[
“<all_urls>”
],
“background”:{
“service_worker”:”background.js”
},
“action”:{
“default_title”:”Element Cleaner”,
“default_popup”:”popup.html”
},
“content_scripts”:[
{
“matches”:[
“<all_urls>”
],
“js”:[
“content.js”
],
“run_at”:”document_start”
}
]
}
- Save manifest.json
- Open content.js and paste the following into it:
let selectedElement=null;
let hoverElement=null;
let extensionEnabled=false;
let lastOutline=””;
function checkState(){
chrome.storage.sync.get(
[“enabledSites”],
result=>{
const sites=
Array.isArray(result.enabledSites)
? result.enabledSites
: [];
extensionEnabled=
sites.includes(location.hostname);
if(! extensionEnabled){
removeHighlight();
}
}
);
}
function applyHighlight(element){
if(! element) return;
if(hoverElement===element){
return;
}
removeHighlight();
hoverElement=element;
lastOutline=
element.style.outline;
element.style.outline=
“3px solid red”;
element.style.outlineOffset=
“2px”;
}
function removeHighlight(){
if(hoverElement){
hoverElement.style.outline=
lastOutline || “”;
hoverElement.style.outlineOffset=”;
}
hoverElement=null;
lastOutline=””;
}
document.addEventListener(
“mousemove”,
event=>{
if(! extensionEnabled){
return;
}
const element=
event.target;
if(
element &&
element! ==document.body &&
element! ==document.documentElement
){
applyHighlight(element);
}
},
True
);
document.addEventListener(
“mouseleave”,
()=>{
removeHighlight();
},
True
);
document.addEventListener(
“contextmenu”,
event=>{
if(! extensionEnabled){
return;
}
selectedElement=
event.target;
applyHighlight(selectedElement);
},
True
);
chrome.storage.onChanged.addListener(()=>{
checkState();
});
chrome.runtime.onMessage.addListener(
message=>{
if(message.action===”remove_element”){
if(
extensionEnabled &&
selectedElement
){
selectedElement.remove();
selectedElement=null;
}
}
if(message.action===”remove_parent_element”){
if(
extensionEnabled &&
selectedElement
){
const parent=
selectedElement.parentElement;
if(parent){
parent.remove();
}
selectedElement=null;
}
}
}
);
checkState();
- Save content.js
- Open background.js and paste the following into it:
const REMOVE_MENU_ID=”remove_element”;
const REMOVE_PARENT_MENU_ID=”remove_parent_element”;
function getHostname(url){
try{
return new URL(url).hostname;
}catch(e){
return “”;
}
}
function getEnabledSites(){
return new Promise(resolve=>{
chrome.storage.sync.get(
[“enabledSites”],
result=>{
resolve(
Array.isArray(result.enabledSites)
? result.enabledSites
: []
);
}
);
});
}
async function isEnabledForTab(tab){
if(! tab || ! tab.url){
return false;
}
const hostname=getHostname(tab.url);
const sites=await getEnabledSites();
return sites.includes(hostname);
}
function createContextMenu(){
chrome.contextMenus.removeAll(()=>{
chrome.contextMenus.create({
id:REMOVE_MENU_ID,
title:”Delete item”,
contexts:[“all”]
});
chrome.contextMenus.create({
id:REMOVE_PARENT_MENU_ID,
title:”Delete parent element”,
contexts:[“all”]
});
});
}
async function refreshMenu(tabId,url){
const enabled=
(await getEnabledSites())
.includes(getHostname(url));
if(enabled){
createContextMenu();
}else{
chrome.contextMenus.removeAll();
}
}
chrome.runtime.onInstalled.addListener(()=>{
chrome.contextMenus.removeAll();
});
chrome.storage.onChanged.addListener(()=>{
chrome.tabs.query(
{}
tabs=>{
tabs.forEach(tab=>{
if(tab.url){
refreshMenu(
tab.id,
tab.url
);
}
});
}
);
});
chrome.tabs.onActivated.addListener(info=>{
chrome.tabs.get(
info.tabId,
tab=>{
if(tab && tab.url){
refreshMenu(
tab.id,
tab.url
);
}
}
);
});
chrome.tabs.onUpdated.addListener(
(tabId,changeInfo,tab)=>{
if(changeInfo.url){
refreshMenu(
tabId,
changeInfo.url
);
}
}
);
chrome.contextMenus.onClicked.addListener(
async(info,tab)=>{
if(! await isEnabledForTab(tab)){
return;
}
chrome.tabs.sendMessage(
tab.id,
{
action:info.menuItemId
}
);
}
);
- Save background.js
- Open popup.html and paste the following into it:
<! DOCTYPE html>
<html lang=”ru”>
<head>
<meta charset=”UTF-8″>
<title>Element Cleaner</title>
<style>
body{
width:350px;
padding:14px;
margin:0;
font-family:Arial,sans-serif;
background:#f7f7f7;
color:#222;
}
h2{
margin:0 0 12px 0;
font-size:20px;
}
.description{
font-size:12px;
opacity:.75;
line-height:1.4;
margin-bottom:12px;
}
.panel{
background:white;
border:1px solid #d5d5d5;
padding:10px;
margin-bottom:12px;
}
.caption{
font-size:12px;
opacity:.7;
}
.current-site{
margin-top:6px;
font-weight:bold;
word-break:break-all;
}
.status{
margin-top:8px;
padding:6px;
text-align:center;
border:1px solid #ddd;
font-size:12px;
}
button{
width:100%;
padding:8px;
margin-top:8px;
cursor:pointer;
}
.sites-title{
margin-bottom:8px;
}
.sites-list{
max-height:170px;
overflow-y:auto;
border:1px solid #ddd;
background:#fff;
}
.site-row{
display:flex;
justify-content:space-between;
align-items:center;
padding:6px;
border-bottom:1px solid #eee;
font-size:12px;
}
.site-name{
overflow:hidden;
text-overflow:ellipsis;
}
.delete-button{
width:auto;
margin:0;
padding:3px 8px;
}
.empty{
padding:8px;
opacity:.6;
font-size:12px;
}
.footer{
margin-top:10px;
text-align:center;
font-size:11px;
opacity:.5;
}
</style>
</head>
<body>
<h2>
Element Cleaner
</h2>
<div class=”description”>
The extension is fully enabled only on selected sites.
On the remaining pages, it does not add items to the context menu.
</div>
<div class=”panel”>
<div class=”caption”>
Current website:
</div>
<div
id=”currentSite”
class=”current-site”
>
Definition…
</div>
<div
id=”status”
class=”status”
>
Checking the status…
</div>
<button
id=”toggleButton”
>
Loading…
</button>
</div>
<div class=”panel”>
<div class=”sites-title”>
Active sites:
</div>
<div
id=”sitesList”
class=”sites-list”
>
</div>
<button
id=”addButton”
>
Add the current website
</button>
</div>
<div class=”footer”>
Element Cleaner • Site control
</div>
<script src=”popup.js”></script>
</body>
</html>
- Save popup.html
- Open popup.js and paste the following:
const currentSiteElement =
document.getElementById(“currentSite”);
const statusElement =
document.getElementById(“status”);
const toggleButton =
document.getElementById(“toggleButton”);
const addButton =
document.getElementById(“addButton”);
const sitesListElement =
document.getElementById(“sitesList”);
let currentHostname=””;
let enabledSites=[];
function getCurrentTab(){
return new Promise(resolve=>{
chrome.tabs.query(
{
active:true,
currentWindow:true
},
tabs=>{
if(tabs && tabs[0]){
resolve(tabs[0]);
}else{
resolve(null);
}
}
);
});
}
function extractHostname(url){
try{
return new URL(url).hostname;
}catch(error){
return “”;
}
}
function loadEnabledSites(){
return new Promise(resolve=>{
chrome.storage.sync.get(
[“enabledSites”],
result=>{
if(
result &&
Array.isArray(result.enabledSites)
){
resolve(
result.enabledSites
);
}else{
resolve([]);
}
}
);
});
}
function saveEnabledSites(list){
return new Promise(resolve=>{
chrome.storage.sync.set(
{
enabledSites:list
},
()=>{
resolve();
}
);
});
}
function isEnabled(site){
return enabledSites.includes(site);
}
function updateStatus(){
if(isEnabled(currentHostname)){
statusElement.textContent=
“Extension is active on this site”;
toggleButton.textContent=
“Disable the extension on the site”;
}else{
statusElement.textContent=
“Extension is disabled on this site”;
toggleButton.textContent=
“Enable the extension on the site”;
}
}
function renderCurrentSite(){
currentSiteElement.textContent=
currentHostname || “Not found”;
updateStatus();
}
function renderSites(){
sitesListElement.innerHTML=””;
if(enabledSites.length===0){
const empty=
document.createElement(“div”);
empty.className=”empty”;
empty.textContent=
“There are no active sites”;
sitesListElement.appendChild(empty);
return;
}
enabledSites.forEach(site=>{
const row=
document.createElement(“div”);
row.className=
“site-row”;
const name=
document.createElement(“div”);
name.className=
“site-name”;
name.textContent=
site;
const button=
document.createElement(“button”);
button.className=
“delete-button”;
button.textContent=
“Delete”;
button.onclick=
async()=>{
enabledSites=
enabledSites.filter(
item=>
item! ==site
);
await saveEnabledSites(
enabledSites
);
renderSites();
renderCurrentSite();
};
row.appendChild(name);
row.appendChild(button);
sitesListElement.appendChild(row);
});
}
async function toggleSite(){
if(! currentHostname){
return;
}
if(isEnabled(currentHostname)){
enabledSites=
enabledSites.filter(
item=>
item! ==currentHostname
);
}else{
enabledSites.push(
currentHostname
);
}
await saveEnabledSites(
enabledSites
);
renderSites();
renderCurrentSite();
}
async function addCurrentSite(){
if(! currentHostname){
return;
}
if(! isEnabled(currentHostname)){
enabledSites.push(
currentHostname
);
await saveEnabledSites(
enabledSites
);
}
renderSites();
renderCurrentSite();
}
function bindEvents(){
toggleButton.onclick=
toggleSite;
addButton.onclick=
addCurrentSite;
}
async function init(){
const tab=
await getCurrentTab();
if(! tab){
return;
}
currentHostname=
extractHostname(tab.url);
enabledSites=
await loadEnabledSites();
renderCurrentSite();
renderSites();
bindEvents();
}
document.addEventListener(
“DOMContentLoaded”,
Init
);
- Save popup.js
How do I start using the extension?
It’s simple:
- Open Chrome and click the “three dots.”
- Next, click “Extensions,”
- The next step is “Manage extensions”
- And finally – “Load unpacked extension.” Select our folder here. Make sure you’ve enabled the extension for the specific site, and that’s it – enjoy!
Instead of conclusions
It may seem like a small thing, but it’s a nice touch.
Why put up with full-screen banners that barely let you see the site’s content when you can make your life easier and your browsing experience more comfortable in just half an hour?
So, friends, give it a try – we wish you a more comfortable browsing experience!
- 5
- 0
- 0
- By rating
- In order