Adds a "Copy" button next to PR title on GitHub (works on navigation)
// ==UserScript==
// @name GitHub PR Title Copier (Improved)
// @namespace http://tampermonkey.net/
// @version 0.5
// @description Adds a "Copy" button next to PR title on GitHub (works on navigation)
// @match https://github.com/*/pull/*
// @grant window.onurlchange
// @license MIT
// ==/UserScript==
(function () {
'use strict';
function addCopyButton() {
const titleEl = document.querySelector('h1[data-component="PH_Title"]');
if (!titleEl || document.querySelector('#pr-title-copy-btn')) return;
const titleTextEl = titleEl.querySelector('span');
if (!titleTextEl) return;
const copyBtn = document.createElement('button');
copyBtn.id = 'pr-title-copy-btn';
copyBtn.textContent = '📋 Copy';
copyBtn.className = 'btn btn-sm';
copyBtn.style.marginLeft = '10px';
copyBtn.style.verticalAlign = 'middle';
copyBtn.addEventListener('click', async (e) => {
e.preventDefault();
try {
const textToCopy = titleTextEl.textContent.trim();
await navigator.clipboard.writeText(textToCopy);
copyBtn.textContent = '✅';
setTimeout(() => {
copyBtn.textContent = '📋 Copy';
}, 1500);
} catch (err) {
console.error('Copy failed:', err);
}
});
titleEl.appendChild(copyBtn);
}
document.addEventListener('turbo:load', addCopyButton);
if (window.onurlchange === null) {
window.addEventListener('urlchange', () => {
setTimeout(addCopyButton, 500);
});
}
addCopyButton();
const observer = new MutationObserver(() => {
if (!document.querySelector('#pr-title-copy-btn')) {
addCopyButton();
}
});
observer.observe(document.body, { childList: true, subtree: true });
})();