Adds copy buttons for Reference Number - Invoice Number in payment history
// ==UserScript==
// @name Copy Invoice File Name
// @namespace https://openai.com
// @version 1.1
// @description Adds copy buttons for Reference Number - Invoice Number in payment history
// @match https://imos.churchofjesuschrist.org/vendor-management/*
// @grant GM_setClipboard
// @run-at document-idle
// ==/UserScript==
(function () {
'use strict';
console.log('[Copy Ref-Inv] Script loaded');
function processTable() {
const table = document.querySelector('table.payment-history-table');
if (!table) {
console.log('[Copy Ref-Inv] Table not found.');
return;
}
console.log('[Copy Ref-Inv] Processing table...');
// Add column header if not already present
const headerRow = table.querySelector('thead tr');
if (headerRow && !headerRow.querySelector('.imos-thead-directive-th-wrapper-copy')) {
const th = document.createElement('th');
th.classList.add('ng-scope', 'imos-thead-directive-th-wrapper-print', 'imos-thead-directive-th-wrapper-copy');
th.setAttribute('ng-class', "'imos-thead-directive-th-wrapper-' + key");
const divSwitch = document.createElement('div');
divSwitch.setAttribute('ng-switch', 'th.headingType');
const divSwitchWhen = document.createElement('div');
divSwitchWhen.setAttribute('ng-switch-when', 'text');
divSwitchWhen.classList.add('ng-scope');
const labelDiv = document.createElement('div');
labelDiv.classList.add('field-label', 'current-sorted-column');
labelDiv.setAttribute('ng-click', "imosThead.sortBy(key)");
const spanLong = document.createElement('span');
spanLong.classList.add('field-label-long', 'ng-binding');
spanLong.textContent = 'Copy Ref - Inv';
const spanShort = document.createElement('span');
spanShort.classList.add('field-label-short', 'ng-binding');
const arrowUp = document.createElement('span');
arrowUp.classList.add('up-arrow', 'ng-hide');
arrowUp.setAttribute('ng-show', "imosThead.shouldShowArrow(key, 'up')");
const arrowDown = document.createElement('span');
arrowDown.classList.add('down-arrow', 'ng-hide');
arrowDown.setAttribute('ng-show', "imosThead.shouldShowArrow(key, 'down')");
labelDiv.appendChild(spanLong);
labelDiv.appendChild(spanShort);
labelDiv.appendChild(arrowUp);
labelDiv.appendChild(arrowDown);
divSwitchWhen.appendChild(labelDiv);
divSwitch.appendChild(divSwitchWhen);
th.appendChild(divSwitch);
headerRow.appendChild(th);
console.log('[Copy Ref-Inv] Header added.');
}
const bodytable = document.querySelector('.payment-history-table-body-section');
if (!bodytable) {
console.log('[Copy Ref-Inv] Body table not found.');
return;
}
const tbodies = bodytable.querySelectorAll('tbody');
tbodies.forEach((tbody, index) => {
const row = tbody.querySelector('tr');
if (!row) return;
if (row.querySelector('.copy-cell')) {
console.log(`[Copy Ref-Inv] Row ${index} already processed.`);
return;
}
const cells = row.querySelectorAll('td');
if (cells.length < 3) {
console.log(`[Copy Ref-Inv] Row ${index} skipped (not enough columns).`);
return;
}
const ref = cells[0].innerText.trim();
const invoice = cells[2].innerText.trim();
if (!ref || !invoice) {
console.log(`[Copy Ref-Inv] Row ${index} missing ref/invoice.`);
return;
}
const toCopy = `${ref} - ${invoice}`;
console.log(`[Copy Ref-Inv] Row ${index}: "${toCopy}"`);
const td = document.createElement('td');
td.className = 'copy-cell';
const btn = document.createElement('button');
btn.innerText = 'Copy';
btn.title = `Copy "${toCopy}"`;
btn.style.cursor = 'pointer';
btn.style.padding = '2px 6px';
btn.style.border = '1px solid #ccc';
btn.style.borderRadius = '4px';
btn.style.background = '#f0f0f0';
btn.style.fontSize = '13px';
btn.onclick = () => {
GM_setClipboard(toCopy);
console.log(`[Copy Ref-Inv] Copied: "${toCopy}"`);
btn.textContent = '✅';
setTimeout(() => btn.textContent = 'Copy', 1200);
};
td.appendChild(btn);
row.appendChild(td);
});
}
// 🐒 Add floating monkey button
function addFloatingButton() {
if (document.querySelector('#copy-monkey-button')) return;
const btn = document.createElement('button');
btn.id = 'copy-monkey-button';
btn.textContent = '🐒';
btn.title = 'Click to add Copy buttons';
btn.style.position = 'fixed';
btn.style.bottom = '20px';
btn.style.right = '20px';
btn.style.width = '48px';
btn.style.height = '48px';
btn.style.borderRadius = '50%';
btn.style.border = 'none';
btn.style.background = '#0091bc';
btn.style.color = 'white';
btn.style.fontSize = '24px';
btn.style.boxShadow = '0 2px 6px rgba(0,0,0,0.3)';
btn.style.zIndex = '9999';
btn.style.cursor = 'pointer';
// 🐒 Monkey jump + spin animation
const style = document.createElement('style');
style.textContent =
`@keyframes monkey-jump-spin {
0% { transform: translateY(0) rotate(0deg); }
30% { transform: translateY(-100px) rotate(180deg); }
60% { transform: translateY(0) rotate(360deg); }
100% { transform: translateY(0) rotate(360deg); }
}
#copy-monkey-button.animate {
animation: monkey-jump-spin 0.9s ease-in-out;
}`
;
document.head.appendChild(style);
btn.onclick = () => {
console.log('[Copy Ref-Inv] 🐒 Button clicked!');
btn.classList.remove('animate');
void btn.offsetWidth; // force reflow
btn.classList.add('animate');
processTable();
};
document.body.appendChild(btn);
}
// ⌨️ Add Ctrl + M shortcut to run the script
document.addEventListener('keydown', function (e) {
if (e.ctrlKey && e.key.toLowerCase() === 'm') {
e.preventDefault();
console.log('[Copy Ref-Inv] Ctrl+M pressed!');
processTable();
}
});
// Run once on load
window.addEventListener('load', () => {
addFloatingButton();
});
})();