- 2
- 0
- 0
Как создать собственное расширение для Хром, которое убирает мусор с сайта
Думаем, почти у каждого возникала пассивная борьба с мусором на веб-сайте, в которой пользователь так и не одерживал желаемой победы.
Как вы понимаете, речь идет о многочисленных рекламных объявлениях на сайтах, которые часто мешают просматривать материал, всплывающие окна и т. п. Кому-то это безразлично, а для кого-то — настоящий кошмар.
Что ж, спасибо технологиям, которые позволяют решить эту проблему и устранить неудобства при просмотре сайтов. В статье мы разберем, как создать расширение, которое убирает мусор и позволяет комфортно пользоваться браузером.
Подробности ищите ниже. Поехали разбираться!
Немного о структуре расширения
Наше расширение будет состоять из:
- manifest.json — файл, который даст понять браузеру, что это именно расширение.
- content.js — файл, в котором будет сосредоточена основная логика работы расширения.
- background.js — логика работы контекстного меню.
- popup.html — меню управления включением и выключением расширения на веб-сайтах.
- popup.js — логика предыдущего меню.
Как создать это расширение?
Сначала нужно создать папку с любым именем, а уже в ней создаем 5 вышеупомянутых файлов (manifest.json, content.js, background.js, popup.html, popup.js).
Далее следуем следующему алгоритму действий:
- Открываем manifest.json и вставляем в него:
{
“manifest_version”:3,
“name”:”Element Cleaner Per Site”,
“version”:”2.0.0″,
“description”:”Удаление элементов страниц через контекстное меню с включением по отдельным сайтам.”,
“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”
}
]
}
- Сохраняем manifest.json
- Открываем content.js и вставляем в него:
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();
- Сохраняем content.js
- Открываем background.js и вставляем:
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:”Удалить элемент”,
contexts:[“all”]
});
chrome.contextMenus.create({
id:REMOVE_PARENT_MENU_ID,
title:”Удалить родительский элемент”,
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
}
);
}
);
- Сохраняем background.js
- Открываем popup.html и вставляем:
<!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”>
Расширение полностью включается только на выбранных сайтах.
На остальных страницах оно не добавляет пункты в контекстное меню.
</div>
<div class=”panel”>
<div class=”caption”>
Текущий сайт:
</div>
<div
id=”currentSite”
class=”current-site”
>
Определение…
</div>
<div
id=”status”
class=”status”
>
Проверка состояния…
</div>
<button
id=”toggleButton”
>
Загрузка…
</button>
</div>
<div class=”panel”>
<div class=”sites-title”>
Активные сайты:
</div>
<div
id=”sitesList”
class=”sites-list”
>
</div>
<button
id=”addButton”
>
Добавить текущий сайт
</button>
</div>
<div class=”footer”>
Element Cleaner • Site control
</div>
<script src=”popup.js”></script>
</body>
</html>
- Сохраняем popup.html
- Открываем popup.js и вставляем:
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=
“Расширение активно на этом сайте”;
toggleButton.textContent=
“Выключить расширение на сайте”;
}else{
statusElement.textContent=
“Расширение выключено на этом сайте”;
toggleButton.textContent=
“Включить расширение на сайте”;
}
}
function renderCurrentSite(){
currentSiteElement.textContent=
currentHostname || “Не найден”;
updateStatus();
}
function renderSites(){
sitesListElement.innerHTML=””;
if(enabledSites.length===0){
const empty=
document.createElement(“div”);
empty.className=”empty”;
empty.textContent=
“Нет активных сайтов”;
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=
“Удалить”;
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
);
- Сохраняем popup.js
Как начать использовать расширение?
Здесь всё просто:
- Откройте Chrome и нажмите на «три точки».
- Далее — «Расширения»,
- следующий шаг — «Управление расширениями»
- И, наконец, — «Загрузить распакованное расширение». Здесь выбираем нашу папку. Убедитесь, что вы включили расширение для конкретного сайта, и всё — наслаждайтесь!
Вместо выводов
Казалось бы, мелочь, а как же приятно.
Зачем терпеть полноэкранные баннеры, из-за которых едва просматривается содержание сайта, если за полчаса можно упростить себе жизнь и сделать использование браузера более комфортным.
Так что, друзья, пробуйте, пользуйтесь — желаем вам больше браузерного комфорта!
- 2
- 0
- 0
- По рейтингу
- По порядку