// ==UserScript==
// @name Input Text Logger
// @namespace https://github.com/putsan
// @author @putsan.bsky.social
// @version 0.1.2
// @description Track continuous text input on websites and save to Tampermonkey's local storage
// @icon https://github.com/putsan/Tampermonkey_scripts/blob/1b111563ad358762c1611a7e1c48544cd4fcf833/resources/icons/image_2023-12-27_22-31-58.png?raw=true
// @include *
// @grant GM_setValue
// @grant GM_getValue
// ==/UserScript==
(function () {
"use strict";
// --- Variables Initialization ---
let currentText = "";
let lastDomain = "";
let lastTimestamp = "";
let inactivityTimer;
// --- Styles for the Popup ---
const popupStyle = `
position: fixed;
bottom: 100px;
right: 10px;
display: none;
flex-direction: column;
gap: 10px;
width: 200px;
padding: 10px;
background: white;
border: 1px solid black;
z-idex: 999;
`;
// --- External CSS Library Link (Pure.css) ---
const pureCssLink = document.createElement('link');
pureCssLink.href = 'https://cdn.jsdelivr.net/npm/[email protected]/build/pure-min.css';
pureCssLink.rel = 'stylesheet';
pureCssLink.type = 'text/css';
// Додавання створеного тегу до секції head веб-сторінки
document.head.appendChild(pureCssLink);
// --- Function to Save Data ---
/**
* Saves text, domain, and timestamp to Tampermonkey's local storage.
* @param {string} newText - The new text to save.
* @param {string} newDomain - The domain from which the text was captured.
* @param {string} newTimestamp - The timestamp when the text was saved.
*/
function saveData(newText, newDomain, newTimestamp) {
// Отримання існуючих даних
let existingData = GM_getValue("savedText", []);
console.log(23, "до", GM_getValue("savedText"));
// Додавання нових даних
existingData.unshift({
text: newText,
domain: newDomain,
timestamp: newTimestamp,
});
// Збереження оновлених даних
GM_setValue("savedText", existingData);
console.log(31, "після", GM_getValue("savedText"));
}
// --- Inactivity Timer Reset Function ---
function resetInactivityTimer() {
clearTimeout(inactivityTimer);
inactivityTimer = setTimeout(() => {
if (currentText.length > 0) {
saveData(currentText, lastDomain, lastTimestamp);
currentText = "";
}
}, 10000); // 10 секунд неактивності
}
document.addEventListener("input", function (event) {
const target = event.target;
if (
(target.tagName === "INPUT" && target.type !== "password") ||
target.tagName === "TEXTAREA"
) {
const domain = window.location.hostname;
const timestamp = new Date().toISOString();
if (domain !== lastDomain) {
if (currentText.length > 0) {
saveData(currentText, lastDomain, lastTimestamp);
}
currentText = target.value;
lastDomain = domain;
lastTimestamp = timestamp;
} else {
currentText = target.value;
}
resetInactivityTimer();
}
});
// Обробник події натискання клавіші
document.addEventListener("keydown", function (event) {
if (event.key === "Enter") {
const domain = window.location.hostname;
const timestamp = new Date().toISOString();
if (currentText.length > 0) {
saveData(currentText, domain, timestamp);
currentText = "";
}
}
});
window.addEventListener("blur", function () {
if (currentText.length > 0) {
saveData(currentText, lastDomain, lastTimestamp);
currentText = "";
}
});
window.addEventListener("beforeunload", function () {
if (currentText.length > 0) {
saveData(currentText, lastDomain, lastTimestamp);
}
});
// --- Function to Create Popup ---
function createPopup() {
const popupHTML = `
<div id="tmPopup" class="pure-u-1-3" style="${popupStyle}">
<button id="viewTextBtn" class="pure-button pure-button-primary">Переглянути текст</button>
<button id="deleteDataBtn" class="button-warning pure-button">Очистити дані</button>
</div>
`;
document.body.insertAdjacentHTML("beforeend", popupHTML);
// Обробник для кнопки перегляду тексту
document.getElementById("viewTextBtn").addEventListener("click", function () {
const savedData = GM_getValue("savedText", []);
const newTab = window.open();
const head = newTab.document.head;
const link = newTab.document.createElement('link');
link.rel = 'stylesheet';
link.href = 'https://cdn.jsdelivr.net/npm/[email protected]/build/pure-min.css';
head.appendChild(link);
// Стилізація вкладки
const style = newTab.document.createElement('style');
style.textContent = `
body { margin: 0; font-family: sans-serif; background-color: #e7e7e7; }
.card { margin-bottom: 15px; padding: 15px; border-radius: 4px; box-shadow: 0 2px 4px rgba(0, 0, 0, .1); }
.domain { color: #333; font-size: 14px; }
.timestamp { color: #666; font-size: 12px; }
.text { margin-top: 10px; }
`;
head.appendChild(style);
const body = newTab.document.body;
// Групування даних за доменом
const dataByDomain = savedData.reduce((acc, { text, domain, timestamp }) => {
if (!acc[domain]) {
acc[domain] = [];
}
acc[domain].push({ text, timestamp });
return acc;
}, {});
// Функція для генерації кольору на основі домену
function stringToColor(str) {
let hash = 0;
for (let i = 0; i < str.length; i++) {
hash = str.charCodeAt(i) + ((hash << 5) - hash);
}
let colour = '#';
for (let i = 0; i < 3; i++) {
let value = (hash >> (i * 8)) & 0xFF;
colour += ('00' + value.toString(16)).substr(-2);
}
return colour;
}
// Створення карточок з даними
Object.keys(dataByDomain).forEach(domain => {
const entries = dataByDomain[domain];
entries.forEach(({ text, timestamp }) => {
const card = newTab.document.createElement('div');
card.className = 'card';
card.style.backgroundColor = stringToColor(domain);
const textDiv = newTab.document.createElement('div');
textDiv.className = 'text';
textDiv.textContent = text;
card.appendChild(textDiv);
const domainDiv = newTab.document.createElement('div');
domainDiv.className = 'domain';
domainDiv.textContent = `Домен: ${domain}`;
card.appendChild(domainDiv);
const timestampDiv = newTab.document.createElement('div');
timestampDiv.className = 'timestamp';
timestampDiv.textContent = `Час: ${new Date(timestamp).toLocaleString()}`;
card.appendChild(timestampDiv);
body.appendChild(card);
});
});
});
document
.getElementById("deleteDataBtn")
.addEventListener("click", function () {
GM_setValue("savedText", []);
});
}
// Виклик функції для створення попапа
createPopup();
// Створення круглої кнопки
const circleBtnHTML = `
<div id="circleBtn" style="width: 35px; height: 35px; border-radius: 50%; background-color: green; position: fixed; bottom: 100px; right: 10px; z-index: 9999;">
<img src="https://github.com/putsan/Tampermonkey_scripts/blob/1b111563ad358762c1611a7e1c48544cd4fcf833/resources/icons/image_2023-12-27_22-31-58.png?raw=true" style="width: 35px; height: 35px; border-radius: 50%;">
</div>
`;
document.body.insertAdjacentHTML("beforeend", circleBtnHTML);
const circleBtn = document.getElementById("circleBtn");
const tmPopup = document.getElementById("tmPopup");
// Функція для розкриття попапа
function togglePopup() {
if (tmPopup.style.display === "none") {
tmPopup.style.display = "flex";
circleBtn.style.display = "none";
}
}
// Функція для закриття попапа
function closePopup() {
tmPopup.style.display = "none";
circleBtn.style.display = "block";
}
// Додавання обробника подій
circleBtn.addEventListener("click", togglePopup);
window.addEventListener("click", function (event) {
// Перевірка, чи клік був зроблений поза `circleBtn` та `tmPopup`
if (!circleBtn.contains(event.target) && !tmPopup.contains(event.target)) {
closePopup();
}
});
})();