Strava Text Auto-Selector

Automatically selects text in specific Strava elements and displays a notification near the cursor. Also allows right-click to copy text.

目前為 2024-12-13 提交的版本,檢視 最新版本

// ==UserScript==
// @name         Strava Text Auto-Selector
// @namespace    https://github.com/Nick2bad4u/UserScripts
// @version      1.0.6
// @description  Automatically selects text in specific Strava elements and displays a notification near the cursor. Also allows right-click to copy text.
// @author       Nick2bad4u
// @license      UnLicense
// @homepageURL  https://github.com/Nick2bad4u/UserScripts
// @grant        none
// @include      *://*.strava.com/activities/*
// @include      *://*.strava.com/athlete/training
// @icon         https://www.google.com/s2/favicons?sz=64&domain=strava.com
// ==/UserScript==

(function() {
    'use strict';

    // Log when the script starts
    console.log('Strava Text Auto-Selector script loaded.');

    // Wait for the page to fully load
    window.addEventListener('load', function() {
        console.log('Page fully loaded, initializing script.');

        // Delay script execution for 500 ms
        setTimeout(initializeScript, 500);
    });

    function initializeScript() {
        console.log('Initializing script after delay.');

        const selectors = [
            '#search-results > tbody > tr:nth-child(n) > td.view-col.col-title > a',
            '.content',
            '#heading > div > div.row.no-margins.activity-summary-container > div.spans8.activity-summary.mt-md.mb-md > div.details-container > div > h1'
        ];
        const summarySelector = '.summaryGridDataContainer';

        // Function to add the event listener to target elements
        function addContextMenuListener(element) {
            console.log('Adding right-click event listener to element:', element);

            element.addEventListener('contextmenu', function(event) {
                console.log('Right-click detected on element:', element);

                event.preventDefault();
                console.log('Default right-click menu prevented.');

                const range = document.createRange();
                if (element.classList.contains('summaryGridDataContainer')) {
                    const textNode = element.childNodes[0];
                    range.selectNodeContents(textNode);
                    console.log('Text range selected:', textNode.textContent);
                } else {
                    range.selectNodeContents(element);
                    console.log('Text range selected:', element.textContent);
                }

                const selection = window.getSelection();
                selection.removeAllRanges();
                selection.addRange(range);
                console.log('Text added to selection.');

                const copiedText = selection.toString();
                console.log('Text copied to clipboard:', copiedText);

                navigator.clipboard.writeText(copiedText).then(() => {
                    console.log('Clipboard write successful.');
                    showNotification(event.clientX, event.clientY, 'Text Copied!');
                }).catch(() => {
                    console.log('Clipboard write failed.');
                    showNotification(event.clientX, event.clientY, 'Failed to Copy!');
                });
            });
        }

        // Query elements and add event listeners initially for the first three selectors
        selectors.forEach(selector => {
            const elements = document.querySelectorAll(selector);
            console.log(`Found ${elements.length} elements for selector: ${selector}`);
            elements.forEach(addContextMenuListener);
        });

        // Function to handle the summaryGridDataContainer elements separately
        function handleSummaryGridDataContainer() {
            const elements = document.querySelectorAll(summarySelector);
            console.log(`Found ${elements.length} elements for selector: ${summarySelector}`);
            elements.forEach(addContextMenuListener);
        }

        // MutationObserver to detect changes in the DOM and add event listeners to new summaryGridDataContainer elements
        const observer = new MutationObserver(mutations => {
            mutations.forEach(mutation => {
                mutation.addedNodes.forEach(node => {
                    if (node.nodeType === Node.ELEMENT_NODE) {
                        if (node.matches(summarySelector)) {
                            addContextMenuListener(node);
                        }
                        node.querySelectorAll(summarySelector).forEach(addContextMenuListener);
                    }
                });
            });
        });

        observer.observe(document.body, { childList: true, subtree: true });
        console.log('MutationObserver set up to monitor the DOM for summaryGridDataContainer.');

        // Handle existing summaryGridDataContainer elements initially
        handleSummaryGridDataContainer();
    }

    function showNotification(x, y, message) {
        console.log('Displaying notification:', message);

        const notification = document.createElement('div');
        notification.textContent = message;
        notification.style.position = 'absolute';
        notification.style.left = `${x + 10}px`;
        notification.style.top = `${y + 10}px`;
        notification.style.background = 'rgba(0, 0, 0, 0.8)';
        notification.style.color = 'white';
        notification.style.padding = '5px 10px';
        notification.style.borderRadius = '5px';
        notification.style.fontSize = '12px';
        notification.style.zIndex = '1000';
        notification.style.pointerEvents = 'none';

        document.body.appendChild(notification);
        console.log('Notification added to DOM.');

        setTimeout(() => {
            notification.remove();
            console.log('Notification removed from DOM.');
        }, 2000);
    }
})();

QingJ © 2025

镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址