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.

Dovrai installare un'estensione come Tampermonkey, Greasemonkey o Violentmonkey per installare questo script.

You will need to install an extension such as Tampermonkey to install this script.

Dovrai installare un'estensione come Tampermonkey o Violentmonkey per installare questo script.

Dovrai installare un'estensione come Tampermonkey o Userscripts per installare questo script.

Dovrai installare un'estensione come ad esempio Tampermonkey per installare questo script.

Dovrai installare un gestore di script utente per installare questo script.

(Ho già un gestore di script utente, lasciamelo installare!)

Dovrai installare un'estensione come ad esempio Stylus per installare questo stile.

Dovrai installare un'estensione come ad esempio Stylus per installare questo stile.

Dovrai installare un'estensione come ad esempio Stylus per installare questo stile.

Dovrai installare un'estensione per la gestione degli stili utente per installare questo stile.

Dovrai installare un'estensione per la gestione degli stili utente per installare questo stile.

Dovrai installare un'estensione per la gestione degli stili utente per installare questo stile.

(Ho già un gestore di stile utente, lasciamelo installare!)

// ==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);
	}
})();