Complete Copy for Gmail

Copy an e-mail including subject and details

이 스크립트를 설치하려면 Tampermonkey, Greasemonkey 또는 Violentmonkey와 같은 확장 프로그램이 필요합니다.

You will need to install an extension such as Tampermonkey or Violentmonkey to install this script.

이 스크립트를 설치하려면 Tampermonkey 또는 Violentmonkey와 같은 확장 프로그램이 필요합니다.

이 스크립트를 설치하려면 Tampermonkey 또는 Userscripts와 같은 확장 프로그램이 필요합니다.

이 스크립트를 설치하려면 Tampermonkey와 같은 확장 프로그램이 필요합니다.

이 스크립트를 설치하려면 유저 스크립트 관리자 확장 프로그램이 필요합니다.

(이미 유저 스크립트 관리자가 설치되어 있습니다. 설치를 진행합니다!)

이 스타일을 설치하려면 Stylus와 같은 확장 프로그램이 필요합니다.

이 스타일을 설치하려면 Stylus와 같은 확장 프로그램이 필요합니다.

이 스타일을 설치하려면 Stylus와 같은 확장 프로그램이 필요합니다.

이 스타일을 설치하려면 유저 스타일 관리자 확장 프로그램이 필요합니다.

이 스타일을 설치하려면 유저 스타일 관리자 확장 프로그램이 필요합니다.

이 스타일을 설치하려면 유저 스타일 관리자 확장 프로그램이 필요합니다.

(이미 유저 스타일 관리자가 설치되어 있습니다. 설치를 진행합니다!)

// ==UserScript==
// @name         Complete Copy for Gmail
// @namespace    https://www.fiverr.com/ahkdev
// @version      2025-04-21
// @description  Copy an e-mail including subject and details
// @author       skygate2012
// @match        https://mail.google.com/*
// @icon         https://www.google.com/s2/favicons?sz=64&domain=google.com
// @grant        GM_addStyle
// @license      MIT
// ==/UserScript==

(function() {
	'use strict';

	GM_addStyle(`
	.copy-complete-btn {
	    width: 20px;
        height: 20px;
		margin-left: 20px;
        cursor: pointer;
        display: inline-block;
	    user-select: none;
		background-image: url('data:image/svg+xml,%3Csvg%20viewBox%3D%220%20-960%20960%20960%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%3E%3Cpath%20d%3D%22M120-220v-80h80v80h-80zm0-140v-80h80v80h-80zm0-140v-80h80v80h-80zM260-80v-80h80v80h-80zm100-160q-33%200-56.5-23.5T280-320v-480q0-33%2023.5-56.5T360-880h360q33%200%2056.5%2023.5T800-800v480q0%2033-23.5%2056.5T720-240H360zm0-80h360v-480H360v480zm40%20240v-80h80v80h-80zm-200%200q-33%200-56.5-23.5T120-160h80v80zm340%200v-80h80q0%2033-23.5%2056.5T540-80zM120-640q0-33%2023.5-56.5T200-720v80h-80zm420%2080z%22%2F%3E%3C%2Fsvg%3E');
	}

	.copy-complete-btn:before {
        content: "";
        display: block;
        opacity: 0;
		width: 200%;
        height: 200%;
        transition-duration: .15s;
        transition-timing-function: cubic-bezier(0.4,0,0.2,1);
		position: relative;
        bottom: -10px;
        left: -10px;
        right: -10px;
        top: -10px;
        background: none;
        border-radius: 50%;
        box-sizing: border-box;
        transform: scale(0);
        transition-property: transform, opacity;
	}

	.copy-complete-btn:hover:before {
	    background-color: rgba(32, 33, 36, .12);
        border: none;
        box-shadow: inset 0 0 0 1px rgb(189, 193, 198);
        opacity: .5;
        -webkit-transform: scale(1);
        transform: scale(1);
    }

	.copy-complete-btn:active:before {
	    opacity: 1;
	}
	`);

	new MutationObserver((mutationRecords, observer) => {
		document.querySelectorAll('[data-message-id]:not([data-ccgprocessed])').forEach((message) => {
			const copyButton = document.createElement('div');
			copyButton.role = 'button';
			copyButton.dataset.tooltip = 'Copy Complete';
			copyButton.className = 'copy-complete-btn';
			copyButton.tabIndex = 0;
			copyButton.addEventListener('click', (event) => {
				const subject = document.querySelector('[data-thread-perm-id]')?.textContent.trim() || '';
				const detailsButton = message.querySelector('div[aria-haspopup="true"]:nth-of-type(2)');
				detailsButton.click();
				detailsButton.click();
				const detailsTable = message.querySelector('[style^="visibility"] table');
				const detailsTableClone = message.querySelector('[style^="visibility"] table').cloneNode(true);
				detailsTableClone.querySelectorAll('a[href]').forEach((link) => link.remove());
				const details = Array.from(detailsTableClone.rows).map(row => Array.from(row.children).map(cell => cell.innerText.trim()).join(" ")).join('\n');

				const body = (message.querySelector('[class*=msg]') || message.querySelector('[data-hash]')?.previousSibling)?.innerText?.trim() || "";

				const content =
`${subject}

${details}

${body}`;

				navigator.clipboard.writeText(content);
				detailsTableClone.remove();
				toast('Copied', 1750);
			});
			message.querySelector('[role="button"]').insertAdjacentElement('afterend', copyButton);
			message.dataset.ccgprocessed = true;
		});
	}).observe(document.documentElement, {
		childList: true,
		subtree: true
	});

	function toast(message, timeout = 3000) {
		let t = document.createElement('div');
		t.textContent = message;
		t.style.cssText = 'position: fixed; bottom: 20px; left: 50%; transform: translateX(-50%); background-color: rgba(0, 0, 0, 0.7); color: white; padding: 10px 20px; border-radius: 5px; z-index: 9999;';
		document.body.appendChild(t);
		setTimeout(() => t.remove(), timeout);
	};

})();