Skip to content

Instantly share code, notes, and snippets.

@tianheg
Last active May 11, 2024 14:08
Show Gist options
  • Save tianheg/4d860adc121936524adbd42af547aff3 to your computer and use it in GitHub Desktop.
Save tianheg/4d860adc121936524adbd42af547aff3 to your computer and use it in GitHub Desktop.
Add a 'Copy' button to flomo each memo
// ==UserScript==
// @name Copy Memo Content
// @version 0.2
// @description Adds a copy button to each memo block to copy its content
// @source https://gist.github.com/tianheg/4d860adc121936524adbd42af547aff3
// @match https://m.tianheg.org/*
// ==/UserScript==
(function() {
'use strict';
// Function to copy text to clipboard
function copyToClipboard(text) {
return navigator.clipboard.writeText(text).then(() => {
console.log('Async: Copying to clipboard was successful!');
}).catch((err) => {
console.error('Async: Could not copy text: ', err);
});
}
// Function to handle the click event
function handleButtonClick(event) {
const button = event.target;
const memoContentElement = button.closest('.group').querySelector('div.group > div:nth-child(2) > div:nth-child(1)');
// Clone the content element to work with it without altering the page
const clonedContentElement = memoContentElement.cloneNode(true);
let memoContent = '';
// Function to recursively get the text content of a node
function getNodeText(node) {
if (node.nodeType === Node.TEXT_NODE) {
// Append text node content
memoContent += node.nodeValue;
} else if (node.nodeType === Node.ELEMENT_NODE) {
if (node.tagName === 'A') {
// Append the text content and the href for anchor elements
memoContent += node.href;
} else if (node.tagName === 'BR') {
// Handle line breaks
memoContent += '\n';
} else if (node.tagName === 'P') {
// Append a new line for paragraph elements after getting their content
Array.from(node.childNodes).forEach(getNodeText);
memoContent += '\n'; // Add a new line after a paragraph
} else {
// Recursively get text for other elements
Array.from(node.childNodes).forEach(getNodeText);
}
}
}
// Start processing the content from the root element
Array.from(memoContentElement.childNodes).forEach(getNodeText);
// Trim the last newline character
memoContent = memoContent.trim();
copyToClipboard(memoContent).then(() => {
// Change button text to 'Copied!'
button.innerText = 'Copied!';
// Set a timeout to revert the button text back to 'Copy' after 2 seconds
setTimeout(() => {
button.innerText = 'Copy';
}, 500);
}).catch((err) => {
// Handle any errors that occur during copy
console.error('Failed to copy text: ', err);
button.innerText = 'Failed to copy';
setTimeout(() => {
button.innerText = 'Copy';
}, 2000);
});
}
// Function to add buttons to memo blocks
function addCopyButtons(memo) {
if (memo.querySelector('.copy-btn')) return;
const copyButton = document.createElement('button');
copyButton.innerText = 'Copy';
copyButton.className = 'copy-btn text-gray-500 dark:text-gray-400';
copyButton.style.border = 'none';
copyButton.style.padding = '5px 10px';
copyButton.style.borderRadius = '5px';
copyButton.style.marginLeft = '10px';
copyButton.style.cursor = 'pointer';
copyButton.style.fontSize = '12px';
const tools = memo.querySelector('.group .flex .shrink-0 .flex');
if (tools) {
tools.appendChild(copyButton);
copyButton.addEventListener('click', handleButtonClick);
}
}
const observer = new MutationObserver(mutations => {
mutations.forEach(mutation => {
if (mutation.addedNodes) {
mutation.addedNodes.forEach(node => {
if (node.classList && node.classList.contains('group') && node.querySelector('.text-gray-800')) {
addCopyButtons(node);
}
});
}
});
});
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