Skip to content

Instantly share code, notes, and snippets.

@ethanquix
Created July 23, 2020 22:24
Show Gist options
  • Save ethanquix/3f5e6cd3938e84eecaf70ca7ea4fb688 to your computer and use it in GitHub Desktop.
Save ethanquix/3f5e6cd3938e84eecaf70ca7ea4fb688 to your computer and use it in GitHub Desktop.
// ==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