// ==UserScript== // @name 微信公众号插入HTML // @namespace http://tampermonkey.net/ // @version 1.0 // @description 一键粘贴HTML并渲染展示 // @author 您 // @match https://mp.weixin.qq.com/cgi-bin/appmsg* // @match https://mp.weixin.qq.com/cgi-bin/operate_appmsg* // @match https://mp.weixin.qq.com/cgi-bin/home* // @grant none // @downloadURL https://raw.githubusercontent.com/joeseesun/qiaomu-userscripts/main/%E5%BE%AE%E4%BF%A1%E5%85%AC%E4%BC%97%E5%8F%B7%E6%8F%92%E5%85%A5%E7%BD%91%E9%A1%B5%E4%BB%A3%E7%A0%81/weixin_editor_helper.js // @updateURL https://raw.githubusercontent.com/joeseesun/qiaomu-userscripts/main/%E5%BE%AE%E4%BF%A1%E5%85%AC%E4%BC%97%E5%8F%B7%E6%8F%92%E5%85%A5%E7%BD%91%E9%A1%B5%E4%BB%A3%E7%A0%81/weixin_editor_helper.js // @homepageURL https://github.com/joeseesun/qiaomu-userscripts // @supportURL https://github.com/joeseesun/qiaomu-userscripts/issues // ==/UserScript== (function() { 'use strict'; // 直接创建固定位置的按钮 function createButton() { // 创建按钮 const button = document.createElement('button'); button.textContent = '插入HTML'; button.title = '插入HTML内容 (先复制HTML到剪贴板)'; button.style.position = 'fixed'; button.style.right = '10px'; button.style.top = '60px'; // 大约位于工具栏位置 button.style.zIndex = '9999'; button.style.backgroundColor = '#2ecc71'; button.style.color = 'white'; button.style.border = 'none'; button.style.borderRadius = '4px'; button.style.padding = '6px 10px'; button.style.cursor = 'pointer'; button.style.fontSize = '14px'; button.style.fontWeight = 'normal'; button.style.boxShadow = '0 2px 5px rgba(0,0,0,0.2)'; // 悬停样式 button.onmouseover = function() { this.style.backgroundColor = '#27ae60'; }; button.onmouseout = function() { this.style.backgroundColor = '#2ecc71'; }; // 点击事件 button.addEventListener('click', async function(e) { e.preventDefault(); e.stopPropagation(); try { // 获取剪贴板内容 const clipboardContent = await getClipboardContent(); if (clipboardContent) { // 尝试插入内容 const success = insertHTMLToEditor(clipboardContent); if (success) { showNotification('HTML内容已成功插入', 'success'); } else { showNotification('插入失败,请查看控制台', 'error'); } } else { showNotification('未获取到HTML内容', 'warning'); } } catch (error) { console.error('处理剪贴板失败:', error); showNotification('获取剪贴板内容失败', 'error'); } }); // 添加到页面 document.body.appendChild(button); } // 显示通知 function showNotification(message, type = 'info') { const notification = document.createElement('div'); notification.style.position = 'fixed'; notification.style.top = '20px'; notification.style.left = '50%'; notification.style.transform = 'translateX(-50%)'; notification.style.padding = '10px 15px'; notification.style.borderRadius = '4px'; notification.style.zIndex = '10000'; notification.style.fontSize = '14px'; notification.style.boxShadow = '0 2px 10px rgba(0,0,0,0.2)'; // 根据类型设置样式 if (type === 'error') { notification.style.backgroundColor = '#e74c3c'; notification.style.color = 'white'; } else if (type === 'success') { notification.style.backgroundColor = '#2ecc71'; notification.style.color = 'white'; } else if (type === 'warning') { notification.style.backgroundColor = '#f39c12'; notification.style.color = 'white'; } else { notification.style.backgroundColor = '#3498db'; notification.style.color = 'white'; } notification.textContent = message; document.body.appendChild(notification); // 自动移除通知 setTimeout(() => { if (document.body.contains(notification)) { notification.style.opacity = '0'; notification.style.transition = 'opacity 0.5s ease'; setTimeout(() => { if (document.body.contains(notification)) { document.body.removeChild(notification); } }, 500); } }, 3000); } // 从剪贴板获取内容 async function getClipboardContent() { return new Promise((resolve) => { // 创建隐藏的textarea用于粘贴 const textarea = document.createElement('textarea'); textarea.style.position = 'fixed'; textarea.style.left = '-9999px'; textarea.style.top = '0px'; document.body.appendChild(textarea); // 聚焦并发送粘贴通知 textarea.focus(); // 显示粘贴提示 const pasteHint = document.createElement('div'); pasteHint.style.position = 'fixed'; pasteHint.style.top = '50%'; pasteHint.style.left = '50%'; pasteHint.style.transform = 'translate(-50%, -50%)'; pasteHint.style.backgroundColor = 'rgba(0,0,0,0.8)'; pasteHint.style.color = 'white'; pasteHint.style.padding = '15px 20px'; pasteHint.style.borderRadius = '5px'; pasteHint.style.zIndex = '10000'; pasteHint.style.fontSize = '16px'; pasteHint.textContent = '请按 Ctrl+V 粘贴剪贴板内容'; document.body.appendChild(pasteHint); // 处理粘贴事件 const pasteHandler = (e) => { e.preventDefault(); // 移除提示 document.body.removeChild(pasteHint); // 获取粘贴的内容 const clipboardData = e.clipboardData || window.clipboardData; let content = clipboardData.getData('text/html') || clipboardData.getData('text'); // 删除临时元素 document.body.removeChild(textarea); document.removeEventListener('paste', pasteHandler); resolve(content); }; document.addEventListener('paste', pasteHandler); // 5秒后超时 setTimeout(() => { if (document.body.contains(textarea)) { document.body.removeChild(textarea); } if (document.body.contains(pasteHint)) { document.body.removeChild(pasteHint); } document.removeEventListener('paste', pasteHandler); resolve(null); }, 5000); }); } // 直接向编辑器插入HTML内容 function insertHTMLToEditor(htmlContent) { // 获取编辑器元素 const editorElement = document.querySelector('div[contenteditable="true"].ProseMirror'); if (!editorElement) { console.error('找不到ProseMirror编辑器元素'); return false; } // 找到section元素 const section = editorElement.querySelector('section'); if (!section) { console.error('找不到section元素'); return false; } try { // 保存编辑器焦点 editorElement.focus(); // 直接替换section的innerHTML section.innerHTML = htmlContent; // 触发多个事件通知编辑器内容已更改 triggerEditorUpdate(editorElement); return true; } catch (error) { console.error('插入HTML时发生错误:', error); return false; } } // 触发编辑器更新事件 function triggerEditorUpdate(editorElement) { const events = ['input', 'change', 'keyup', 'blur', 'focus']; events.forEach(eventType => { try { const event = new Event(eventType, { bubbles: true }); editorElement.dispatchEvent(event); } catch (e) { console.error(`触发 ${eventType} 事件失败:`, e); } }); // 创建并触发输入事件 try { const inputEvent = new InputEvent('input', { bubbles: true, cancelable: true, data: null, inputType: 'insertReplacementText' }); editorElement.dispatchEvent(inputEvent); } catch (e) { console.error('触发InputEvent事件失败:', e); } } // 使用MutationObserver等待编辑器加载 function waitForEditor() { return new Promise((resolve) => { // 如果编辑器已存在,直接解析 const editor = document.querySelector('div[contenteditable="true"].ProseMirror'); if (editor) { resolve(editor); return; } // 否则,使用MutationObserver监听DOM变化 const observer = new MutationObserver(() => { const editor = document.querySelector('div[contenteditable="true"].ProseMirror'); if (editor) { observer.disconnect(); resolve(editor); } }); observer.observe(document.body, { childList: true, subtree: true }); // 设置超时,防止无限等待 setTimeout(() => { observer.disconnect(); resolve(null); }, 10000); // 10秒超时 }); } // 初始化 async function init() { // 等待编辑器加载 const editor = await waitForEditor(); if (editor) { createButton(); } } // 启动脚本 init(); })();