您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Prevents scrollbar misalignment when pressing Page Up/Page Down in the prompt input area of contenteditable elements by handling key events and adjusting cursor position accordingly.
当前为
// ==UserScript== // @name Fix Scrollbar Position on Page Up/Page Down in ContentEditable // @name:zh-TW 修正 ContentEditable 中按下 Page Up/Page Down 時滾動條位置不正確問題 // @namespace Violentmonkey Scripts // @match https://chatgpt.com/c/* // @grant none // @version 1.0 // @author JohnnyZhou@TW // @description Prevents scrollbar misalignment when pressing Page Up/Page Down in the prompt input area of contenteditable elements by handling key events and adjusting cursor position accordingly. // @description:zh-TW 當在 contenteditable 元素的提示輸入區域按下 Page Up/Page Down 鍵時,通過處理按鍵事件並調整游標位置,防止滾動條位置錯位。 // @license MIT // ==/UserScript== (function() { 'use strict'; /** * 將游標移動到指定元素的開頭 * @param {HTMLElement} element - 目標元素 */ function setCaretToStart(element) { const range = document.createRange(); const sel = window.getSelection(); // 找到第一個可編輯的子節點 let firstNode = element.querySelector('p, span, div'); if (firstNode) { range.setStart(firstNode, 0); } else { range.setStart(element, 0); } range.collapse(true); sel.removeAllRanges(); sel.addRange(range); } /** * 將游標移動到指定元素的結尾 * @param {HTMLElement} element - 目標元素 */ function setCaretToEnd(element) { const range = document.createRange(); const sel = window.getSelection(); // 找到最後一個可編輯的子節點 let lastNode = getLastEditableNode(element); if (lastNode) { if (lastNode.nodeType === Node.TEXT_NODE) { range.setStart(lastNode, lastNode.textContent.length); } else { range.setStart(lastNode, lastNode.childNodes.length); } } else { range.setStart(element, element.childNodes.length); } range.collapse(true); sel.removeAllRanges(); sel.addRange(range); } /** * 遞迴查找最後一個可編輯的子節點 * @param {HTMLElement} element - 目標元素 * @returns {Node} 最後一個可編輯的子節點 */ function getLastEditableNode(element) { if (!element) return null; if (element.lastChild) { return getLastEditableNode(element.lastChild); } return element; } /** * 綁定鍵盤事件到目標元素 * @param {HTMLElement} editableDiv - 可編輯的目標元素 */ function bindKeyEvents(editableDiv) { if (!editableDiv) return; editableDiv.addEventListener('keydown', (event) => { if (event.key === 'PageUp') { event.preventDefault(); // 阻止預設行為 setCaretToStart(editableDiv); // 將游標移動到開頭 } else if (event.key === 'PageDown') { event.preventDefault(); // 阻止預設行為 setCaretToEnd(editableDiv); // 將游標移動到結尾 } }); } /** * 使用 MutationObserver 監聽目標元素的出現 */ function observeDOM() { const observer = new MutationObserver((mutations, obs) => { const editableDiv = document.getElementById('prompt-textarea'); if (editableDiv) { bindKeyEvents(editableDiv); obs.disconnect(); // 停止監聽 } }); observer.observe(document.body, { childList: true, subtree: true }); } // 立即嘗試綁定,如果元素已存在 const existingDiv = document.getElementById('prompt-textarea'); if (existingDiv) { bindKeyEvents(existingDiv); } else { // 如果元素尚未存在,開始監聽 observeDOM(); } })();