您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Adds shortcuts for text colors (Alt+1 for black, Alt+2 for #00a797, Alt+3 for #006057, Alt+4 for #ff3333), opening heading outline (Alt+5), opening text color menu (Alt+7), restoring scroll position before document close (Alt+8), and switch to last selected document tab (Alt+W), and Borders and Shading (Alt+G)
当前为
// ==UserScript== // @name Google Docs Shortcuts // @namespace http://tampermonkey.net/ // @version 1.3 // @license MIT // @description Adds shortcuts for text colors (Alt+1 for black, Alt+2 for #00a797, Alt+3 for #006057, Alt+4 for #ff3333), opening heading outline (Alt+5), opening text color menu (Alt+7), restoring scroll position before document close (Alt+8), and switch to last selected document tab (Alt+W), and Borders and Shading (Alt+G) // @match https://docs.google.com/* // @grant none // ==/UserScript== (function () { 'use strict'; // Key combinations for color shortcuts const COLOR_SHORTCUTS = { '4': { rgb: 'rgb(255, 51, 51)', hex: '#ff3333' }, '3': { rgb: 'rgb(0, 96, 87)', hex: '#006057' }, '2': { rgb: 'rgb(0, 167, 151)', hex: '#00a797' }, '1': { rgb: 'rgb(0, 0, 0)', hex: '#000000' } }; // Key combinations for other shortcuts const TAB_SHORTCUT_KEY = '5'; // Alt + 5 const COLOR_SHORTCUT_KEY = '7'; // Alt + 7 const SCROLL_SHORTCUT_KEY = '8'; // Alt + 8 const TAB_SWITCH_KEY_CODE = 87; // KeyCode for 'W' (Alt + W) const BORDER_SHADING_KEY_CODE = 71; // KeyCode for 'G' (Alt + G) // Constants for Tab Switching const TAB_SWITCH_REFACTORY_PERIOD = 500; // Time in milliseconds let lastSelectedTab = null; let currentSelectedTab = null; let isTabSwitchInProgress = false; // Variable to track whether a tab switch is in progress // Handle keydown events for various shortcuts function handleKeydown(event) { if (event.altKey && !event.ctrlKey) { switch (event.key) { case TAB_SHORTCUT_KEY: // Alt + 5 event.preventDefault(); event.stopImmediatePropagation(); clickSelectedTab(); break; case COLOR_SHORTCUT_KEY: // Alt + 7 event.preventDefault(); event.stopImmediatePropagation(); clickTextColorButton(); break; case SCROLL_SHORTCUT_KEY: // Alt + 8 event.preventDefault(); event.stopImmediatePropagation(); restoreScrollPosition(); break; case '4': // Shortcut for #ff3333 case '3': // Shortcut for #006057 case '2': // Shortcut for #00a797 case '1': // Shortcut for #000000 event.preventDefault(); event.stopPropagation(); event.stopImmediatePropagation(); const { rgb, hex } = COLOR_SHORTCUTS[event.key]; setTimeout(() => clickColor(rgb, hex), 50); break; } } } // Handle Alt + W separately (for tab switching) function handleAltWKey(event) { if (event.altKey && event.keyCode === TAB_SWITCH_KEY_CODE) { // Alt + W event.preventDefault(); event.stopImmediatePropagation(); clickLastSelectedTab(); } } // Handle Alt + G (Borders and Shading) function handleAltGKey(event) { if (event.altKey && event.keyCode === BORDER_SHADING_KEY_CODE) { // Alt + G event.preventDefault(); event.stopImmediatePropagation(); clickBordersAndShading(); } } // Attach the keydown event listener to both the top window and iframe function attachKeyListener() { const iframe = document.querySelector('iframe.docs-texteventtarget-iframe'); if (iframe) { const iframeDoc = iframe.contentDocument || iframe.contentWindow.document; iframeDoc.addEventListener('keydown', handleKeydown, true); iframeDoc.addEventListener('keydown', handleAltWKey, true); // Attach Alt+W listener to iframe iframeDoc.addEventListener('keydown', handleAltGKey, true); // Attach Alt+G listener to iframe console.log('Key listener attached to iframe.'); } else { console.log('Iframe not found. Retrying...'); setTimeout(attachKeyListener, 1000); // Retry after 1 second } window.addEventListener('keydown', handleKeydown, true); // Attach to top window window.addEventListener('keydown', handleAltWKey, true); // Attach Alt+W listener to top window window.addEventListener('keydown', handleAltGKey, true); // Attach Alt+G listener to top window console.log('Key listener attached to top window.'); } // Common Functions // Function to simulate a click event (for tab, color button, and color pickers) function clickElement(element) { const mouseDown = new MouseEvent('mousedown', { bubbles: true, cancelable: true, view: window }); const mouseUp = new MouseEvent('mouseup', { bubbles: true, cancelable: true, view: window }); const clickEvt = new MouseEvent('click', { bubbles: true, cancelable: true, view: window }); element.dispatchEvent(mouseDown); element.dispatchEvent(mouseUp); element.dispatchEvent(clickEvt); console.log('Simulated real mouse event sequence on', element); } // Click on the selected tab (Alt + 5) - reverted to the original working selector function clickSelectedTab() { const tabElement = document.querySelector('.chapter-item-label-and-buttons-container[aria-selected="true"]'); if (tabElement) { clickElement(tabElement); console.log('Tab clicked'); } else { console.log('Tab element not found.'); } } // Click the text color button (Alt + 7) function clickTextColorButton() { const textColorButton = document.querySelector('div[aria-label="Text color"]'); // Updated selector if (textColorButton) { clickElement(textColorButton); console.log('Text color button clicked'); } else { console.log('Text color button not found.'); } } // Simulate click on a color in the color picker (Alt+1, Alt+2, Alt+3, Alt+4) function clickColor(rgb, hex) { let colorElement; if (hex === '#000000') { colorElement = document.querySelector('td[aria-label="black"]'); // Special handling for black } else { colorElement = document.querySelector(`div[style*="${rgb}"]`); // Custom color selector } if (colorElement) { clickElement(colorElement); console.log(`Simulated click on color ${hex}`); } else { console.log(`Color element for ${hex} not found.`); } } // Function to click the "Borders and Shading" menu function clickBordersAndShading() { const bordersAndShadingButton = document.querySelector('span[aria-label="Borders and shading b'); // Updated selector if (bordersAndShadingButton) { clickElement(bordersAndShadingButton); console.log('Borders and shading menu clicked'); } else { console.log('Borders and shading menu item not found.'); } } // Function to get the current document's unique identifier (URL) function getDocumentId() { const url = new URL(window.location.href); // Create a URL object from the current URL url.hash = ''; // Remove any fragment identifier (e.g., #heading=h.c7jmgehkx73h) return url.toString(); // Return the cleaned URL, including query parameters } // Function to save the scroll position function saveScrollPosition() { const documentId = getDocumentId(); const scrollableElement = document.querySelector('.kix-appview-editor'); if (scrollableElement) { const scrollPosition = scrollableElement.scrollTop; const scrollData = JSON.parse(localStorage.getItem('googleDocsScrollData') || '{}'); scrollData[documentId] = scrollPosition; localStorage.setItem('googleDocsScrollData', JSON.stringify(scrollData)); console.log('Scroll position saved for document:', documentId, scrollPosition); } } // Function to restore the scroll position function restoreScrollPosition() { const documentId = getDocumentId(); const scrollData = JSON.parse(localStorage.getItem('googleDocsScrollData') || '{}'); const scrollPosition = scrollData[documentId]; const scrollableElement = document.querySelector('.kix-appview-editor'); if (scrollableElement && scrollPosition !== undefined) { scrollableElement.scrollTo(0, parseInt(scrollPosition, 10)); console.log('Scroll position restored for document:', documentId, scrollPosition); } else { console.log('No scroll position saved for this document.'); } } // Functions Related to Tab Selection // Function to get all document tabs and subtabs function getTabsAndSubtabs() { const treeItems = document.querySelectorAll('[role="treeitem"]'); return Array.from(treeItems).filter(item => { const ariaLabel = item.getAttribute('aria-label'); return ariaLabel && !ariaLabel.toLowerCase().includes('level'); // Filter out headings }); } // Function to detect and update the current selected tab function getLastSelectedTab() { const selectedTab = document.querySelector('.chapter-item-label-and-buttons-container[aria-selected="true"]'); if (selectedTab) { if (currentSelectedTab !== selectedTab) { lastSelectedTab = currentSelectedTab; } currentSelectedTab = selectedTab; // Update current selected tab console.log('Current selected tab:', selectedTab.getAttribute('aria-label')); // Debugging log } else { console.log('No tab is currently selected.'); } } // Function to simulate a click on the last selected tab function clickLastSelectedTab() { if (isTabSwitchInProgress) return; // Prevent switching if a switch is in progress (refractory period) if (lastSelectedTab && lastSelectedTab !== currentSelectedTab) { console.log('Clicking on last selected tab:', lastSelectedTab.getAttribute('aria-label')); // Debugging log isTabSwitchInProgress = true; // Mark tab switch as in progress clickElement(lastSelectedTab); // Using the clickElement function from the first script // Ensure focus is inside the iframe and the caret is active const iframe = document.querySelector('iframe.docs-texteventtarget-iframe'); if (iframe) { const iframeDoc = iframe.contentDocument || iframe.contentWindow.document; iframe.focus(); // Ensure focus is inside the iframe iframeDoc.body.click(); // Simulate clicking on the body to ensure caret is active console.log('Focus set inside the document and caret activated!'); } // After the refractory period, allow the next tab switch setTimeout(() => { isTabSwitchInProgress = false; }, TAB_SWITCH_REFACTORY_PERIOD); // 500ms refractory period } else { console.log('No valid last selected tab found.'); } } // Initialization // Function to initialize listeners and start updating the last selected tab function initialize() { console.log('Userscript loaded. Ready to detect shortcuts.'); // Update the last selected tab whenever the tab changes setInterval(getLastSelectedTab, 1000); // Update every 1 second // Attach the key listener to detect Alt+W and Alt+G attachKeyListener(); } // Save scroll position before the page unloads window.addEventListener('beforeunload', saveScrollPosition); // Start attaching listeners after the window loads window.addEventListener('load', initialize); })();
QingJ © 2025
镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址