Skip to content

Instantly share code, notes, and snippets.

@unitycoder
Last active April 30, 2025 07:39
Show Gist options
  • Save unitycoder/86968ebaaafac9ed9a609c0f41dbeedc to your computer and use it in GitHub Desktop.
Save unitycoder/86968ebaaafac9ed9a609c0f41dbeedc to your computer and use it in GitHub Desktop.
GreaseMonkey Trello Checklist Exporter
// ==UserScript==
// @name Trello Checklist Exporter
// @namespace https://unitycoder.com/
// @version 1.3
// @description Export Trello card checklists (visible items only) to plain text, download as .txt file. See button in Actions list.
// @author unitycoder_com
// @match https://trello.com/c/*
// @grant none
// ==/UserScript==
(function () {
'use strict';
function extractChecklistData() {
const titleEl = document.querySelector('#card-back-name');
if (!titleEl) return;
let output = `# ${titleEl.textContent.trim()}\n\n`;
const checklistSections = document.querySelectorAll('[data-testid="checklist-section"]');
checklistSections.forEach(section => {
const checklistTitle = section.querySelector('[data-testid="checklist-title"]');
output += `### ${checklistTitle?.textContent.trim()}\n`;
const items = section.querySelectorAll('[data-testid="check-item-container"]');
items.forEach(item => {
const isChecked = item.querySelector('input[type="checkbox"]').checked;
const label = item.querySelector('[data-testid="check-item-name"]');
if (label?.offsetParent !== null) {
output += `- [${isChecked ? 'x' : ' '}] ${label.textContent.trim()}\n`;
}
});
output += '\n';
});
copyToClipboard(output); // Shows Trello "Copied to clipboard" toast
const date = new Date();
const dd = String(date.getDate()).padStart(2, '0');
const mm = String(date.getMonth() + 1).padStart(2, '0');
const yyyy = date.getFullYear();
const formattedDate = `_${dd}${mm}${yyyy}`;
const filename = `${titleEl.textContent.trim().replace(/[\\/:*?"<>|]/g, "_")}${formattedDate}_checklist.txt`;
downloadAsTxt(output, filename);
}
function copyToClipboard(text) {
navigator.clipboard.writeText(text).catch(() => {
const tmp = document.createElement("textarea");
tmp.style.position = "fixed";
tmp.style.opacity = "0";
tmp.value = text;
document.body.appendChild(tmp);
tmp.focus();
tmp.select();
document.execCommand("copy");
document.body.removeChild(tmp);
});
}
function downloadAsTxt(content, filename) {
const blob = new Blob([content], { type: 'text/plain' });
const link = document.createElement('a');
link.href = URL.createObjectURL(blob);
link.download = filename;
link.style.display = 'none';
document.body.appendChild(link);
link.click();
document.body.removeChild(link);
}
function addExportButton() {
if (document.getElementById('exportChecklistBtn')) return;
const shareButton = document.querySelector('[data-testid="card-back-share-button"]');
if (!shareButton) return;
const btn = document.createElement('button');
btn.textContent = '📋 Export Checklist';
btn.id = 'exportChecklistBtn';
btn.style.margin = '5px';
btn.style.padding = '5px';
btn.style.cursor = 'pointer';
btn.onclick = extractChecklistData;
// Insert after the share button
shareButton.parentNode.insertBefore(btn, shareButton.nextSibling);
}
const observer = new MutationObserver(() => {
addExportButton();
});
observer.observe(document.body, { childList: true, subtree: true });
})();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment