Пишем расширение для браузера Chrome для поиска по истории посещенных страниц
Доброго времени суток! В данной статье мы рассмотрим с Вами как можно написать расширение для браузера Chrome, которое позволяет осуществлять поиск по истории, при этом в расширение добавлена и фильтрация по времени.
Файловая структура проекта:
Data:.
│ history.html
│ manifest.json
│
├───images
│ ic_history.png
│
├───popup
│ popup.html
│ popup.js
│
└───scrips
history.js
Для начала рассмотрим файл manifest.json:
{
"manifest_version": 3,
"name": "My history",
"description": "Featured Chrome history",
"version": "1.0",
"action": {
"default_popup": "popup/popup.html",
"default_icon": "images/ic_history.png"
},
"permissions": [
"history",
"tabs",
"activeTab"
]
}
Файл popup/popup.html - отображает кнопку для открытия страницы расширения:
<!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>Hello</title>
</head>
<body>
<div id="extension">
<button id="openHistoryBtn">Open history</button>
</div>
<script src="popup.js"></script>
</body>
</html>
Файл popup/popup.js - при нажатии на кнопку в браузере откроется новое окно, которое отобразит функционал поиска по истории.
const openHistoryBtn = document.getElementById('openHistoryBtn');
openHistoryBtn.addEventListener('click', (e) => {
chrome.tabs.create({ url: 'history.html' });
});
Теперь рассмотрим сам файл history.html, где как раз и располагается вся основная разметка приложения.
<!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>History</title>
<style>
* {
box-sizing: border-box;
}
body {
font-size: 1rem;
}
.container {
max-width: 1368px;
margin: 0 auto;
padding: 0 8px;
}
.row {
display: flex;
gap: 10px;
margin-top: 20px;
}
.md:w-100 {
width: 10%;
}
button {
padding: 8px 16px;
border: 1px solid rgb(12, 113, 245);
border-radius: 5px;
cursor: pointer;
}
.form-input {
width: 100%;
margin-bottom: 8px;
}
.form-input>* {
display: block;
}
.form-input>label {
cursor: pointer;
margin-bottom: 8px;
}
input {
width: 100%;
padding: 8px;
border: 1px solid rgb(12, 113, 245);
border-radius: 5px;
}
input:focus {
outline: 1px solid rgb(251, 202, 5);
}
table,
th,
td {
border: 1px solid black;
border-collapse: collapse;
}
table {
overflow-wrap: break-word;
table-layout: fixed;
width: 100%;
border: 1px solid rgb(8, 130, 237);
text-align: center;
margin-top: 20px;
}
table>tr {
padding: 8px;
}
table td,
table th {
padding: 8px;
}
</style>
</head>
<body>
<div id="app">
<div class="container">
<h2>Chrome history search</h2>
<form>
<div class="form-input">
<label for="searchTermText">Search in title</label>
<input type="text" id="searchTermText" required />
</div>
<div class="row">
<div class="form-input">
<label for="searchResultsMaxCount">Search results max count</label>
<input type="number" id="searchResultsMaxCount" value="100" required />
</div>
<div class="form-input">
<label for="startTimeDateTimePicker">Start date</label>
<input type="date" id="startTimeDateTimePicker" style="font-size: 0.74rem" required />
</div>
</div>
<div class="row">
<button class="button" id="startSearchButton">Search</button>
</div>
</form>
<table class="table">
<thead>
<tr>
<th>Id</th>
<th>Last visist time</th>
<th>title</th>
<th>Typed count</th>
<th>Url</th>
<th>Visit count</th>
</tr>
</thead>
<tbody id="searchResults"></tbody>
</table>
</div>
</div>
<script src="scrips/history.js"></script>
</body>
</html>
А теперь рассмотрим файл scripts/history.js:
const app = document.getElementById('app');
const searchResults = document.getElementById('searchResults');
const startSearchButton = document.getElementById('startSearchButton');
function convert_days_to_timestamp(days) {
const microsecondsPerWeek = 1000 * 60 * 60 * 24 * days;
return (new Date).getTime() - microsecondsPerWeek;
}
function datetime_format(timestamp) {
if (!timestamp) return '';
let dt_formatted = '';
const dtFormat = new Intl.DateTimeFormat("ru", {
weekday: "short",
year: "numeric",
month: "long",
day: "numeric",
hour: "numeric",
minute: "numeric"
});
try {
dt_formatted = dtFormat.format(new Date(timestamp));
}
catch (e) {
return '';
}
return dt_formatted;
}
function show_history_entries(text, maxResultsCount, startTime) {
// обращаемся к Chrome Extensions API и получаем необходимые данные
chrome.history
.search({
text: text || 'google',
maxResults: maxResultsCount || 100000,
startTime: startTime || new Date('01/01/2022').getTime()
})
.then(entries => {
const rows = entries.map(entry => {
const values = Object.values(entry).map((value, index) => {
let cell = '';
switch (index) {
case 1:
cell = `<td>${datetime_format(value)}</td>`;
break;
case 4:
cell = `<td><a href="${value}">Go</a></td>`;
break;
default:
cell = `<td>${value}</td>`;
break;
}
return cell;
});
return `<tr>${values.join('')}</tr>`;
})
searchResults.innerHTML = rows.join('');
});
}
startSearchButton.addEventListener('click', (e) => {
e.preventDefault();
const searchTermText = document.getElementById('searchTermText');
const searchResultsMaxCount = document.getElementById('searchResultsMaxCount');
const startTimeDateTimePicker = document.getElementById('startTimeDateTimePicker');
const text = searchTermText.value.trim();
const maxCount = Number(searchResultsMaxCount.value.trim());
const startTime = startTimeDateTimePicker.value.trim();
const daysAgo = Date.now() - new Date(startTime).getTime();
console.log(text, maxCount, daysAgo);
show_history_entries(text, maxCount, daysAgo);
});
После всего этого, для установки расширения в браузер нужно зайти в меню установленных расширений, там выбрать галочку для разработчиков и в появившемся меню загрузить расширение из файловой системы.
Вот таким образом мы создали простое расширение для браузера Chrome, которое позволяет вести поиск по истории с дополнительными фильтрами.
-
- Михаил Русаков
Комментарии (0):
Для добавления комментариев надо войти в систему.
Если Вы ещё не зарегистрированы на сайте, то сначала зарегистрируйтесь.