您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Automatically selects text in specific Strava elements and displays a notification near the cursor. Also allows right-click to copy text.
// ==UserScript== // @name Strava Text Auto-Selector // @namespace typpi.online // @version 1.0.9 // @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', '.summaryGrid .summaryGridDataContainer, .inline-stats strong, .inline-stats b', '#heading > div > div.row.no-margins.activity-summary-container > div.spans8.activity-summary.mt-md.mb-md > div.details-container > div > h1', '.ride .segment-effort-detail .effort-details table, .swim .segment-effort-detail .effort-details table', '.activity-description p:only-child', '.activity-description p:first-child', ]; 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); } })();