Created
July 23, 2020 22:24
-
-
Save ethanquix/3f5e6cd3938e84eecaf70ca7ea4fb688 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// ==UserScript== | |
// @name Copy Github PRs | |
// @namespace http://tampermonkey.net/ | |
// @version 0.7 | |
// @description try to take over the world! | |
// @author You | |
// @match https://github.com/* | |
// @grant none | |
// ==/UserScript== | |
(function() { | |
function forNodes(nodes, cb) { | |
for (let idx = 0; idx < nodes.length; idx += 1) { | |
cb(nodes[idx], idx, nodes); | |
} | |
} | |
// https://stackoverflow.com/questions/400212/how-do-i-copy-to-the-clipboard-in-javascript | |
function copyTextToClipboard(text) { | |
var textArea = document.createElement("textarea"); | |
// | |
// *** This styling is an extra step which is likely not required. *** | |
// | |
// Why is it here? To ensure: | |
// 1. the element is able to have focus and selection. | |
// 2. if element was to flash render it has minimal visual impact. | |
// 3. less flakyness with selection and copying which **might** occur if | |
// the textarea element is not visible. | |
// | |
// The likelihood is the element won't even render, not even a flash, | |
// so some of these are just precautions. However in IE the element | |
// is visible whilst the popup box asking the user for permission for | |
// the web page to copy to the clipboard. | |
// | |
// Place in top-left corner of screen regardless of scroll position. | |
textArea.style.position = 'fixed'; | |
textArea.style.top = 0; | |
textArea.style.left = 0; | |
// Ensure it has a small width and height. Setting to 1px / 1em | |
// doesn't work as this gives a negative w/h on some browsers. | |
textArea.style.width = '2em'; | |
textArea.style.height = '2em'; | |
// We don't need padding, reducing the size if it does flash render. | |
textArea.style.padding = 0; | |
// Clean up any borders. | |
textArea.style.border = 'none'; | |
textArea.style.outline = 'none'; | |
textArea.style.boxShadow = 'none'; | |
// Avoid flash of white box if rendered for any reason. | |
textArea.style.background = 'transparent'; | |
textArea.value = text; | |
document.body.appendChild(textArea); | |
textArea.select(); | |
try { | |
var successful = document.execCommand('copy'); | |
var msg = successful ? 'successful' : 'unsuccessful'; | |
console.log('Copying text command was ' + msg + '\n\n' + text); | |
} catch (err) { | |
console.log('Oops, unable to copy'); | |
} | |
document.body.removeChild(textArea); | |
} | |
function hasClasses(el, cls) { | |
cls = typeof cls === "string" ? [cls] : cls; | |
for (let idx = 0; idx < cls.length; idx += 1) { | |
if (el.classList.contains(cls[idx])) { | |
return true; | |
} | |
} | |
return false; | |
} | |
function findParentByClassName(node, cl, cb) { | |
do { | |
if (hasClasses(node, cl)) { | |
cb(node); | |
break; | |
} | |
node = node.parentElement; | |
} while (node); | |
} | |
function pushIssue(iss, text, link) { | |
iss.push('// ' + (text || '').trim() + '\n' + link); | |
} | |
function handleIssue(iss) { | |
iss.push('@here'); | |
return function (no) { | |
let link = no.querySelector('.js-navigation-open'); | |
pushIssue(iss, link.innerText, link.href); | |
}; | |
} | |
function hasPBAction(node) { | |
return node.classList.contains('pb-btn'); | |
} | |
function addPBAction(node) { | |
node.classList.add('pb-btn'); | |
} | |
var REGEX_ELLIPSIS_END = /…$/; | |
var REGEX_ELLIPSIS_START = /^…/; | |
function copyAllPRs() { | |
let nodes = document.querySelectorAll('.js-issue-row .d-table'); | |
let iss = []; | |
let handler = handleIssue(iss); | |
forNodes(nodes, handler); | |
copyTextToClipboard(iss.join('\n\n')); | |
} | |
function copyCheckedPRs() { | |
let iss = []; | |
let handler = handleIssue(iss); | |
forNodes(document.querySelectorAll('.publica-pr,.js-issues-list-check'), function (no) { | |
if (no.checked) { | |
findParentByClassName(no, ['d-table'], handler); | |
} | |
}); | |
copyTextToClipboard(iss.join('\n\n')); | |
} | |
function copyPR() { | |
let iss = ['@here']; | |
pushIssue(iss, document.querySelector('.gh-header-title').innerText, location.href.replace("/files", "")); | |
copyTextToClipboard(iss.join('\n\n')); | |
} | |
function copyTitle() { | |
copyTextToClipboard(document.querySelector('.gh-header-title').innerText); | |
} | |
var REGEX_JIRA_TIX = /^.+\(([^\)]+)\).+$/; | |
function getJiraTix(text) { | |
return (REGEX_JIRA_TIX.exec(text) || [])[1]; | |
} | |
function viewJira() { | |
var tix = getJiraTix(document.querySelector('.gh-header-title').innerText); | |
window.open('https://publica-project.atlassian.net/browse/' + tix, '_blank'); | |
} | |
function viewJira2(ev) { | |
findParentByClassName(ev.target, 'd-table', function (node) { | |
var tix = getJiraTix(node.querySelector('.js-navigation-open').innerText); | |
window.open('https://publica-project.atlassian.net/browse/' + tix, '_blank'); | |
}); | |
} | |
function createButton(parent, id, fn, handler) { | |
if (!parent) { | |
return; | |
} | |
let btn = document.querySelector('#' + id); | |
if (!btn) { | |
btn = fn(); | |
btn.id = id; | |
} | |
btn.removeEventListener('click', handler); | |
btn.addEventListener('click', handler); | |
} | |
function addInputs(parent, name, fn, handler) { | |
forNodes(document.querySelectorAll(parent), function(no) { | |
var el = no.querySelector('.' + name); | |
if (!el) { | |
el = fn(no); | |
el.classList.add(name); | |
} | |
if (handler) { | |
el.removeEventListener('click', handler); | |
el.addEventListener('click', handler); | |
} | |
}); | |
} | |
function fixTitle() { | |
document.querySelector('#merge_title_field').value = document.querySelector('.gh-header-title').innerText; | |
document.querySelector('#merge_message_field').value = ""; | |
} | |
function addPRButtons() { | |
let tbl = document.querySelector('.table-list-header'); | |
createButton(tbl, 'btncopyallprs', function() { | |
let btn = document.createElement('button'); | |
btn.innerText = "copy ALL publica PRs"; | |
tbl.insertBefore(btn, tbl.firstChild); | |
return btn; | |
}, copyAllPRs); | |
createButton(tbl, 'btncopycheckedprs', function() { | |
let btn2 = document.createElement('button'); | |
btn2.innerText = "copy checked publica PRs"; | |
tbl.insertBefore(btn2, document.querySelector('#btncopyallprs').nextElementSibling); | |
return btn2; | |
}, copyCheckedPRs); | |
addInputs('.js-issue-row .d-table>div:first-child', 'btncheckbox', function (no) { | |
let inp = document.createElement('input'); | |
inp.className = 'publica-pr'; | |
inp.style.marginRight = '10px'; | |
inp.type = 'checkbox'; | |
no.insertBefore(inp, no.firstChild); | |
return inp; | |
}); | |
addInputs('.js-issue-row .d-table>div .commit-build-statuses', 'rowsviewjira', function (no) { | |
let btn = document.createElement('button'); | |
btn.innerText = 'view jira'; | |
no.insertBefore(btn, no.lastChild); | |
return btn; | |
}, viewJira2); | |
let actions = document.querySelector('.gh-header-actions'); | |
createButton(actions, 'btncopypr', function() { | |
var btn3 = document.createElement('button'); | |
btn3.innerText = "copy PR"; | |
btn3.style.float = "left"; | |
btn3.style.marginRight = "5px"; | |
actions.insertBefore(btn3, actions.firstChild); | |
return btn3; | |
}, copyPR); | |
createButton(actions, 'btncopytitle', function() { | |
var btn4 = document.createElement('button'); | |
btn4.innerText = "copy title"; | |
btn4.style.float = "left"; | |
btn4.style.marginRight = "5px"; | |
actions.insertBefore(btn4, actions.firstChild); | |
return btn4; | |
}, copyTitle); | |
createButton(actions, 'btnviewjira', function() { | |
var btn = document.createElement('button'); | |
btn.innerText = "view jira"; | |
btn.style.float = "left"; | |
btn.style.marginRight = "5px"; | |
actions.insertBefore(btn, actions.firstChild); | |
return btn; | |
}, viewJira); | |
let sqsh = document.querySelector('.btn-group-squash .js-details-target'); | |
if (sqsh) { | |
sqsh.removeEventListener('click', fixTitle); | |
sqsh.addEventListener('click', fixTitle, false); | |
} | |
let timeline = document.querySelector('.timeline-new-comment'); | |
if (timeline) { | |
let head = timeline.querySelector('.discussion-topic-header input'); | |
let cont = timeline.querySelector('.write-content textarea'); | |
if (head && cont && REGEX_ELLIPSIS_END.test(head.value) && REGEX_ELLIPSIS_START.test(cont.value)) { | |
head.value = head.value.replace('…', '') + cont.value.replace('…', ''); | |
cont.value = ''; | |
} | |
} | |
} | |
function debounce(time, cb) { | |
var idx = 0; | |
return function() { | |
if (idx) { clearTimeout(idx); } | |
var id = setTimeout(function() { | |
if (id === idx) { | |
cb(); | |
} | |
}); | |
idx = id; | |
}; | |
} | |
(function(handler) { | |
var cb = debounce(1000, handler); | |
if (document.readyState === 'complete') { | |
cb(); | |
} else { | |
document.addEventListener('readystatechange', () => { | |
if (document.readyState === 'complete') { | |
cb(); | |
} | |
}); | |
} | |
window.addEventListener('click', cb, false); | |
window.addEventListener('focus', cb, false); | |
})(function() { | |
addPRButtons(); | |
}); | |
})(); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment