// ==UserScript== // @name 编辑网页 // @namespace http://tampermonkey.net/ // @version 1.2.5 // @description 这是一个能编辑任何网页文本的扩展 // @author yhu // @license GPL-3.0 // @match *://*/* // @grant none // ==/UserScript== (function() { 'use strict'; let currentElement = null; let isSourceEditing = false; let originalHtml = ''; let sourceTextarea = null; function edit(el) { if (el.isContentEditable || el.closest('button,a,[role="button"]')) return; if (currentElement) { currentElement.contentEditable = 'false'; currentElement.style.outline = ''; currentElement.style.backgroundColor = ''; currentElement = null; } el.contentEditable = 'true'; el.style.outline = '2px dashed #4a9eff'; el.style.backgroundColor = 'rgba(74,158,255,0.1)'; el.focus(); let obs = new MutationObserver(() => { el.style.color = 'yellow'; obs.disconnect(); }); obs.observe(el, { childList: true, subtree: true, characterData: true }); el.addEventListener('blur', () => { obs.disconnect(); el.contentEditable = 'false'; el.style.outline = ''; el.style.backgroundColor = ''; currentElement = null; }, { once: true }); currentElement = el; } function exitSourceEdit() { if (sourceTextarea) { sourceTextarea.remove(); sourceTextarea = null; } isSourceEditing = false; } document.body.addEventListener('click', (e) => { if (e.detail === 3) { let link = e.target.closest('a'); if (link && link.href) { e.preventDefault(); e.stopPropagation(); window.open(link.href, '_blank'); } return; } if (e.detail === 2) { if (isSourceEditing) { e.preventDefault(); e.stopPropagation(); exitSourceEdit(); return; } e.preventDefault(); e.stopPropagation(); isSourceEditing = true; originalHtml = document.documentElement.outerHTML; let textarea = document.createElement('textarea'); textarea.value = originalHtml; textarea.style.cssText = 'position:fixed;top:0;left:0;width:100%;height:100%;z-index:10000;font-family:monospace;font-size:14px;background:#1e1e1e;color:#d4d4d4;border:none;padding:10px;'; textarea.contentEditable = 'true'; document.body.appendChild(textarea); textarea.focus(); sourceTextarea = textarea; textarea.addEventListener('blur', () => { if (textarea.value !== originalHtml) { let newDoc = textarea.value; document.open(); document.write(newDoc); document.close(); } exitSourceEdit(); }, { once: true }); return; } if (isSourceEditing) return; if (e.target.isContentEditable) return; if (currentElement && !currentElement.contains(e.target)) { currentElement.contentEditable = 'false'; currentElement.style.outline = ''; currentElement.style.backgroundColor = ''; currentElement = null; } let node = e.target; while (node && node.nodeType === Node.TEXT_NODE) node = node.parentElement; if (!node) return; let target = node.closest('p,h1,h2,h3,h4,h5,h6,li,span,div,label,td,th,figcaption,legend'); if (target) { e.preventDefault(); e.stopPropagation(); edit(target); } }, true); })();