DefenderOfBasic / works-in-progress

14 stars 0 forks source link

Adds a button to copy tweet content and link to clipboard when tweets come into view. #33

Open Abezag-Hash opened 3 months ago

Abezag-Hash commented 3 months ago

// ==UserScript== // @name Twitter Copy Button // @namespace http://tampermonkey.net/ // @version 1.2 // @description Adds a button to copy tweet content and link to clipboard when tweets come into view. // @author RadicalRasmalai // @match https://*.x.com/* // @grant GM_setClipboard // ==/UserScript==

(function() { 'use strict';

// Function to add the copy button to each tweet
function addCopyButton(tweet) {
    // Check if the copy button is already added
    if (tweet.querySelector('.copy-button')) return;

    // Create the copy button
    const button = document.createElement('button');
    button.innerText = 'Copy';
    button.className = 'copy-button';
    button.style.position = 'absolute';
    button.style.top = '0px';
    button.style.right = '50px';
    button.style.padding = '5px 10px';
    button.style.backgroundColor = '#1DA1F2';
    button.style.color = '#fff';
    button.style.border = 'none';
    button.style.borderRadius = '5px';
    button.style.cursor = 'pointer';
    button.style.zIndex = '1000'; // Ensure the button appears on top

    // On click, copy the tweet content and link
    button.addEventListener('click', function() {

        const tweetTextElement = tweet.querySelector('[data-testid="tweetText"]');
        const tweetText = tweetTextElement ? tweetTextElement.innerText : 'Tweet content not found';
        const userNameElement = tweet.querySelector('[data-testid="User-Name"]');
        const userName = userNameElement ? userNameElement.innerText : 'Username not found';

        // Extract tweet link
        const tweetLinkElement = tweet.querySelector('a[href*="/status/"]');
        const tweetLink = tweetLinkElement ? tweetLinkElement.href : 'Link not found';

        // Format the content to copy
        const contentToCopy = `${userName}\nTweet: ${tweetText}\n\nLink: ${tweetLink}`;

        GM_setClipboard(contentToCopy);
        alert('Tweet content and link copied to clipboard!');
    });

    // Position the button in the bottom-right of the tweet
    tweet.style.position = 'relative'; // Ensure the tweet has a positioning context
    tweet.appendChild(button);
}

// Intersection Observer to detect when posts come into view
const observer = new IntersectionObserver((entries) => {
    entries.forEach(entry => {
        if (entry.isIntersecting) {
            addCopyButton(entry.target);  // Add button to the tweet
            entry.target.setAttribute('data-counted', 'true');  // Mark this post as counted
            observer.unobserve(entry.target);  // Stop observing this post
        }
    });
}, {
    threshold: 0.5
});

// Function to observe new posts
function observePosts() {
    const posts = document.querySelectorAll('article:not([data-counted])');  // Select posts that have not been counted
    posts.forEach(post => {
        observer.observe(post);
    });
}

// Initial observation
observePosts();

// Observe mutations in the document to handle dynamically loaded content
const mutationObserver = new MutationObserver(observePosts);
mutationObserver.observe(document, { childList: true, subtree: true });

})();