// ==UserScript==
// @name Contextual Clipboard Assistant
// @name:de Kontextueller Zwischenablage-Assistent
// @name:es Asistente de Portapapeles Contextual
// @name:fr Assistant Presse-papiers Contextuel
// @name:it Assistente Appunti Contestuale
// @name:ja コンテキストクリップボードアシスタント
// @name:zh-CN 上下文剪贴板助手
// @name:ru Контекстный Помощник Буфера Обмена
// @description Adds a floating toolbar with clipboard-related actions like copy, cut, paste, and save to file. The script integrates multilingual support (English, German, Spanish, French, Italian, Japanese, Chinese, Russian).
// @description:de Fügt eine schwebende Symbolleiste mit Zwischenablageaktionen wie Kopieren, Ausschneiden, Einfügen und Speichern hinzu. Das Skript bietet mehrsprachige Unterstützung (Englisch, Deutsch, Spanisch, Französisch, Italienisch, Japanisch, Chinesisch, Russisch).
// @description:es Agrega una barra de herramientas flotante con acciones relacionadas con el portapapeles como copiar, cortar, pegar y guardar en un archivo. El script integra soporte multilingüe (inglés, alemán, español, francés, italiano, japonés, chino, ruso).
// @description:fr Ajoute une barre d'outils flottante avec des actions liées au presse-papiers comme copier, couper, coller et enregistrer dans un fichier. Le script intègre un support multilingue (anglais, allemand, espagnol, français, italien, japonais, chinois, russe).
// @description:it Aggiunge una barra degli strumenti flottante con azioni relative agli appunti come copia, taglia, incolla e salva su file. Lo script integra il supporto multilingue (inglese, tedesco, spagnolo, francese, italiano, giapponese, cinese, russo).
// @description:ja コピー、切り取り、貼り付け、ファイルへの保存など、クリップボード関連のアクションを提供する浮動ツールバーを追加します。スクリプトは多言語サポート(英語、ドイツ語、スペイン語、フランス語、イタリア語、日本語、中国語、ロシア語)を統合しています。
// @description:zh-CN 添加一个浮动工具栏,具有与剪贴板相关的操作,例如复制、剪切、粘贴和保存到文件。脚本集成了多语言支持(英语、德语、西班牙语、法语、意大利语、日语、中文、俄语)。
// @description:ru Добавляет плавающую панель инструментов с действиями, связанными с буфером обмена, такими как копирование, вырезание, вставка и сохранение в файл. Скрипт включает поддержку нескольких языков (английский, немецкий, испанский, французский, итальянский, японский, китайский, русский).
// @icon https://cdn-icons-png.flaticon.com/128/5435/5435494.png
// @namespace http://tampermonkey.net/
// @version 2024.12.27
// @author Copiis
// @license MIT
// @match *://*/*
// @grant GM_addStyle
// @grant GM_getValue
// @grant GM_setValue
// @grant GM_notification
// @grant GM_registerMenuCommand
// @grant GM_unregisterMenuCommand
// @grant clipboardRead
// @grant clipboardWrite
// @grant unsafeWindow
// @run-at document-end
// ==/UserScript==
(function () {
'use strict';
let insertMode = false; // Flag to track if we are in "Insert" mode
const translations = {
de: { insertInstruction: "Klicken oder markieren Sie Text, wo der Inhalt der Zwischenablage eingefügt werden soll.", fileSaved: "Datei gespeichert als:" },
en: { insertInstruction: "Click or select text where you want to paste the clipboard content.", fileSaved: "File saved as:" },
es: { insertInstruction: "Haga clic o seleccione el texto donde desea pegar el contenido del portapapeles.", fileSaved: "Archivo guardado como:" },
fr: { insertInstruction: "Cliquez ou sélectionnez le texte où vous souhaitez coller le contenu du presse-papiers.", fileSaved: "Fichier enregistré sous :" },
it: { insertInstruction: "Fare clic o selezionare il testo in cui incollare il contenuto degli appunti.", fileSaved: "File salvato come:" },
zh: { insertInstruction: "单击或选择要粘贴剪贴板内容的文本。", fileSaved: "文件已保存为:" },
ja: { insertInstruction: "クリップボードの内容を貼り付けたい場所をクリックまたは選択します。", fileSaved: "ファイルとして保存されました:" },
ru: { insertInstruction: "Щелкните или выберите текст, куда нужно вставить содержимое буфера обмена.", fileSaved: "Файл сохранен как:" },
default: { insertInstruction: "Click or select text where you want to paste the clipboard content.", fileSaved: "File saved as:" }
};
const browserLanguage = navigator.language.slice(0, 2);
const messages = translations[browserLanguage] || translations.default;
const popup = document.createElement('div');
popup.style.position = 'absolute';
popup.style.backgroundColor = '#282c34';
popup.style.color = '#61dafb';
popup.style.border = '2px solid #20232a';
popup.style.boxShadow = '0 4px 6px rgba(0,0,0,0.3)';
popup.style.padding = '10px';
popup.style.borderRadius = '10px';
popup.style.display = 'none';
popup.style.zIndex = '10000';
popup.style.fontSize = '14px';
popup.style.textAlign = 'center';
popup.style.minWidth = '200px';
const feedback = document.createElement('div');
feedback.style.color = '#76c7c0';
feedback.style.fontSize = '12px';
feedback.style.marginBottom = '5px';
feedback.style.maxWidth = '200px';
feedback.style.wordWrap = 'break-word';
feedback.style.textAlign = 'center';
feedback.style.height = 'auto';
popup.appendChild(feedback);
const actions = [
{ symbol: '📋', action: copyText, title: 'Copy' },
{ symbol: '✂️', action: cutText, title: 'Cut' },
{ symbol: '📥', action: activateInsertMode, title: 'Paste' },
{ symbol: '💾', action: saveToFile, title: 'Save' },
{ symbol: '📝', action: formatMarkdown, title: 'Format (Markdown)' }
];
actions.forEach(({ symbol, action, title }) => {
const button = document.createElement('button');
button.innerHTML = symbol;
button.title = title;
button.style.display = 'inline-block';
button.style.cursor = 'pointer';
button.style.backgroundColor = '#20232a';
button.style.color = '#61dafb';
button.style.border = '1px solid #444';
button.style.borderRadius = '3px';
button.style.padding = '5px';
button.style.margin = '3px';
button.style.fontSize = '18px';
button.addEventListener('click', () => {
action();
button.style.backgroundColor = '#444';
setTimeout(() => {
button.style.backgroundColor = '#20232a';
}, 200);
});
popup.appendChild(button);
});
document.body.appendChild(popup);
document.addEventListener('mouseup', (event) => {
const selectedText = window.getSelection().toString();
const elementsUnderCursor = document.elementsFromPoint(event.clientX, event.clientY);
const isTextFreeArea = elementsUnderCursor.every((el) => {
const computedStyle = window.getComputedStyle(el);
return el.nodeType !== Node.TEXT_NODE && computedStyle.pointerEvents === 'none';
});
if (selectedText.trim() || isTextFreeArea) {
positionPopup(event.pageX, event.pageY);
popup.style.display = 'block';
}
});
popup.addEventListener('mousedown', (event) => {
event.stopPropagation();
});
document.addEventListener('mousedown', (event) => {
if (!popup.contains(event.target) && !insertMode) {
hidePopup();
}
});
document.addEventListener('keydown', () => {
if (!insertMode) {
hidePopup();
}
});
function activateInsertMode() {
insertMode = true;
document.body.style.cursor = 'crosshair';
showFeedback(messages.insertInstruction);
}
document.addEventListener('click', (event) => {
if (!insertMode) return;
if (popup.contains(event.target)) return;
navigator.clipboard.readText().then((clipboardText) => {
if (!clipboardText) {
showFeedback('Clipboard is empty.');
return;
}
const selection = window.getSelection();
const range = selection.rangeCount > 0 ? selection.getRangeAt(0) : null;
if (range && !range.collapsed) {
range.deleteContents();
range.insertNode(document.createTextNode(clipboardText));
showFeedback('Replaced!');
} else {
const range = document.caretRangeFromPoint(event.clientX, event.clientY);
if (range) {
range.insertNode(document.createTextNode(clipboardText));
showFeedback('Inserted!');
} else {
showFeedback('Cannot insert here.');
}
}
insertMode = false;
document.body.style.cursor = '';
hidePopup();
}).catch(() => {
showFeedback('Error reading clipboard.');
insertMode = false;
document.body.style.cursor = '';
});
});
function positionPopup(x, y) {
const popupWidth = popup.offsetWidth || 150;
const popupHeight = popup.offsetHeight || 50;
const viewportWidth = window.innerWidth;
const viewportHeight = window.innerHeight;
let adjustedX = x;
let adjustedY = y;
if (x + popupWidth > viewportWidth) {
adjustedX = viewportWidth - popupWidth - 10;
}
if (y + popupHeight > viewportHeight) {
adjustedY = viewportHeight - popupHeight - 10;
}
popup.style.left = `${adjustedX}px`;
popup.style.top = `${adjustedY}px`;
}
function showFeedback(message) {
feedback.textContent = message;
feedback.style.opacity = '1';
setTimeout(() => {
feedback.style.opacity = '0';
}, 2000);
}
function copyText() {
const selectedText = window.getSelection().toString();
if (selectedText.trim()) {
navigator.clipboard.writeText(selectedText).then(() => {
showFeedback('Copied!');
});
}
}
function cutText() {
const selectedText = window.getSelection().toString();
if (selectedText.trim()) {
navigator.clipboard.writeText(selectedText).then(() => {
document.execCommand('delete');
showFeedback('Cut!');
});
}
}
function saveToFile() {
const timestamp = new Date().toISOString().replace(/[:.-]/g, '_');
const fileName = `${timestamp}.txt`;
const selectedText = window.getSelection().toString();
const content = selectedText.trim() ? selectedText : 'No content selected.';
const blob = new Blob([content], { type: 'text/plain' });
const a = document.createElement('a');
a.href = URL.createObjectURL(blob);
a.download = fileName;
a.click();
URL.revokeObjectURL(a.href);
showFeedback(`${messages.fileSaved} ${fileName}`);
}
function formatMarkdown() {
const selectedText = window.getSelection().toString();
if (!selectedText.trim()) {
showFeedback('No text selected for formatting.');
return;
}
const formattedText = `**${selectedText}**`; // Example Markdown formatting
navigator.clipboard.writeText(formattedText).then(() => {
showFeedback('Formatted as Markdown and copied!');
});
}
function hidePopup() {
popup.style.display = 'none';
}
})();