您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Word-style text editor: format text, insert images/tables, auto-save, all from the userscript menu.
// ==UserScript== // @name Drawaria Word Office - Text Editor // @description Word-style text editor: format text, insert images/tables, auto-save, all from the userscript menu. // @version 1.0 // @match https://drawaria.online/* // @match https://*.drawaria.online/* // @icon https://drawaria.online/favicon-32x32.png // @grant GM.setValue // @grant GM.getValue // @grant GM_registerMenuCommand // @license MIT // @namespace https://greasyfork.org/users/1088100 // ==/UserScript== (function() { 'use strict'; console.log('Drawaria Word Processor initializing...'); // Debounce function for performance optimization function debounce(func, wait) { let timeout; return function executedFunction(...args) { const later = () => { clearTimeout(timeout); func(...args); }; clearTimeout(timeout); timeout = setTimeout(later, wait); }; } // Function to create the Word-like text editor function createWordEditor() { console.log('Creating Word editor interface...'); // Create main editor container const editorContainer = document.createElement('div'); editorContainer.id = 'word-editor-container'; editorContainer.style.cssText = ` position: fixed; top: 20px; right: 20px; width: 900px; height: 700px; background: #ffffff; border: 2px solid #d1d5db; border-radius: 12px; box-shadow: 0 20px 25px -5px rgba(0, 0, 0, 0.1), 0 10px 10px -5px rgba(0, 0, 0, 0.04); z-index: 10000; font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; display: flex; flex-direction: column; resize: both; overflow: hidden; min-width: 600px; min-height: 400px; `; // Create title bar const titleBar = document.createElement('div'); titleBar.id = 'word-editor-titlebar'; titleBar.style.cssText = ` background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); color: white; padding: 12px 20px; font-weight: 600; font-size: 16px; border-radius: 10px 10px 0 0; display: flex; justify-content: space-between; align-items: center; cursor: move; `; titleBar.innerHTML = ` <span>📝 Drawaria Word Office</span> <div> <button id="minimize-editor" style="background: rgba(255,255,255,0.2); border: none; color: white; padding: 4px 8px; border-radius: 4px; margin-right: 8px; cursor: pointer;">−</button> <button id="close-editor" style="background: rgba(255,255,255,0.2); border: none; color: white; padding: 4px 8px; border-radius: 4px; cursor: pointer;">×</button> </div> `; // Create toolbar const toolbar = document.createElement('div'); toolbar.id = 'word-editor-toolbar'; toolbar.style.cssText = ` background: #f8fafc; border-bottom: 1px solid #e2e8f0; padding: 12px; display: flex; flex-wrap: wrap; gap: 8px; align-items: center; `; // Toolbar HTML with comprehensive formatting options toolbar.innerHTML = ` <div style="display: flex; gap: 4px; align-items: center; margin-right: 12px;"> <button class="toolbar-btn" data-command="undo" title="Undo">↶</button> <button class="toolbar-btn" data-command="redo" title="Redo">↷</button> </div> <div style="width: 1px; height: 24px; background: #cbd5e0; margin: 0 8px;"></div> <div style="display: flex; gap: 4px; align-items: center; margin-right: 12px;"> <select id="font-family" style="padding: 4px 8px; border: 1px solid #cbd5e0; border-radius: 4px; font-size: 12px;"> <option value="Arial">Arial</option> <option value="Times New Roman">Times New Roman</option> <option value="Helvetica">Helvetica</option> <option value="Georgia">Georgia</option> <option value="Verdana">Verdana</option> <option value="Courier New">Courier New</option> <option value="Comic Sans MS">Comic Sans MS</option> </select> <select id="font-size" style="padding: 4px 8px; border: 1px solid #cbd5e0; border-radius: 4px; font-size: 12px; width: 60px;"> <option value="1">8</option> <option value="2">10</option> <option value="3" selected>12</option> <option value="4">14</option> <option value="5">18</option> <option value="6">24</option> <option value="7">36</option> </select> </div> <div style="width: 1px; height: 24px; background: #cbd5e0; margin: 0 8px;"></div> <div style="display: flex; gap: 4px; align-items: center; margin-right: 12px;"> <button class="toolbar-btn format-btn" data-command="bold" title="Bold"><b>B</b></button> <button class="toolbar-btn format-btn" data-command="italic" title="Italic"><i>I</i></button> <button class="toolbar-btn format-btn" data-command="underline" title="Underline"><u>U</u></button> <button class="toolbar-btn format-btn" data-command="strikeThrough" title="Strikethrough"><s>S</s></button> </div> <div style="width: 1px; height: 24px; background: #cbd5e0; margin: 0 8px;"></div> <div style="display: flex; gap: 4px; align-items: center; margin-right: 12px;"> <input type="color" id="text-color" value="#000000" title="Text Color" style="width: 32px; height: 28px; border: 1px solid #cbd5e0; border-radius: 4px; cursor: pointer;"> <input type="color" id="bg-color" value="#ffffff" title="Highlight Color" style="width: 32px; height: 28px; border: 1px solid #cbd5e0; border-radius: 4px; cursor: pointer;"> </div> <div style="width: 1px; height: 24px; background: #cbd5e0; margin: 0 8px;"></div> <div style="display: flex; gap: 4px; align-items: center; margin-right: 12px;"> <button class="toolbar-btn format-btn" data-command="justifyLeft" title="Align Left">⬅</button> <button class="toolbar-btn format-btn" data-command="justifyCenter" title="Center">⬌</button> <button class="toolbar-btn format-btn" data-command="justifyRight" title="Align Right">➡</button> <button class="toolbar-btn format-btn" data-command="justifyFull" title="Justify">⬍</button> </div> <div style="width: 1px; height: 24px; background: #cbd5e0; margin: 0 8px;"></div> <div style="display: flex; gap: 4px; align-items: center; margin-right: 12px;"> <button class="toolbar-btn" data-command="insertUnorderedList" title="Bullet List">• List</button> <button class="toolbar-btn" data-command="insertOrderedList" title="Numbered List">1. List</button> <button class="toolbar-btn" data-command="outdent" title="Decrease Indent">⬅ Indent</button> <button class="toolbar-btn" data-command="indent" title="Increase Indent">Indent ➡</button> </div> <div style="width: 1px; height: 24px; background: #cbd5e0; margin: 0 8px;"></div> <div style="display: flex; gap: 4px; align-items: center;"> <button class="toolbar-btn" id="insert-table" title="Insert Table">📊 Table</button> <button class="toolbar-btn" id="insert-image" title="Insert Image">🖼️ Image</button> <button class="toolbar-btn" id="insert-link" title="Insert Link">🔗 Link</button> </div> <div style="width: 1px; height: 24px; background: #cbd5e0; margin: 0 8px;"></div> <div style="display: flex; gap: 4px; align-items: center;"> <button class="toolbar-btn" id="save-file" title="Save Document">💾 Save</button> <button class="toolbar-btn" id="load-file" title="Load Document">📂 Load</button> </div> `; // Create editor content area const editorContent = document.createElement('div'); editorContent.style.cssText = ` flex: 1; display: flex; background: #f1f5f9; overflow: hidden; `; // Create document area (like Word's page view) const documentArea = document.createElement('div'); documentArea.id = 'document-area'; documentArea.style.cssText = ` flex: 1; padding: 20px; overflow-y: auto; background: #f1f5f9; display: flex; flex-direction: column; align-items: center; `; // Create the actual document (paper-like) const documentElement = document.createElement('div'); documentElement.contentEditable = true; documentElement.id = 'word-document'; documentElement.style.cssText = ` background: white; min-height: 800px; padding: 60px 80px; margin: 0 auto; width: 100%; max-width: 700px; box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1); border-radius: 8px; font-family: 'Times New Roman', serif; font-size: 12pt; line-height: 1.6; color: #1f2937; outline: none; position: relative; `; documentElement.innerHTML = ` <h1 style="text-align: center; margin-bottom: 30px; color: #1f2937;">Document Title</h1> <p>Start typing your document here. This is a fully functional Microsoft Word-like editor with support for:</p> <ul> <li>Rich text formatting (bold, italic, underline)</li> <li>Font selection and sizing</li> <li>Text alignment and indentation</li> <li>Bullet points and numbered lists</li> <li>Tables and images</li> <li>Real-time editing</li> </ul> <p>Click anywhere to start editing!</p> `; // Create status bar const statusBar = document.createElement('div'); statusBar.id = 'word-editor-status-bar'; statusBar.style.cssText = ` background: #f8fafc; border-top: 1px solid #e2e8f0; padding: 8px 20px; font-size: 12px; color: #64748b; display: flex; justify-content: space-between; align-items: center; `; statusBar.innerHTML = ` <div id="status-info">Ready</div> <div id="document-stats">Words: 0 | Characters: 0</div> `; // Assemble the editor documentArea.appendChild(documentElement); editorContent.appendChild(documentArea); editorContainer.appendChild(titleBar); editorContainer.appendChild(toolbar); editorContainer.appendChild(editorContent); editorContainer.appendChild(statusBar); // Add CSS styles for toolbar buttons const style = document.createElement('style'); style.textContent = ` .toolbar-btn { background: white; border: 1px solid #cbd5e0; padding: 6px 12px; border-radius: 4px; cursor: pointer; font-size: 12px; font-weight: 500; color: #374151; transition: all 0.2s; } .toolbar-btn:hover { background: #f3f4f6; border-color: #9ca3af; } .toolbar-btn:active, .toolbar-btn.active { background: #e5e7eb; border-color: #6b7280; } .format-btn.active { background: #3b82f6; color: white; border-color: #2563eb; } #word-document:focus { box-shadow: 0 0 0 3px rgba(59, 130, 246, 0.1); } #word-document table { border-collapse: collapse; width: 100%; margin: 10px 0; } #word-document table td, #word-document table th { border: 1px solid #cbd5e0; padding: 8px; text-align: left; } #word-document table th { background-color: #f8fafc; font-weight: bold; } #word-document img { max-width: 100%; height: auto; border-radius: 4px; margin: 10px 0; } #word-document a { color: #3b82f6; text-decoration: underline; } #word-document blockquote { border-left: 4px solid #e5e7eb; margin: 16px 0; padding-left: 16px; color: #6b7280; font-style: italic; } `; document.head.appendChild(style); return { editorContainer, documentElement, statusBar }; } // Function to initialize the editor functionality function initializeEditor(editorContainer, documentElement, statusBar) { console.log('Initializing editor functionality...'); // Make title bar draggable let isDragging = false; let dragOffset = { x: 0, y: 0 }; const titleBar = editorContainer.querySelector('#word-editor-titlebar'); titleBar.addEventListener('mousedown', (e) => { if (e.target.tagName === 'BUTTON') return; isDragging = true; const rect = editorContainer.getBoundingClientRect(); dragOffset.x = e.clientX - rect.left; dragOffset.y = e.clientY - rect.top; document.addEventListener('mousemove', handleDrag); document.addEventListener('mouseup', stopDrag); }); function handleDrag(e) { if (!isDragging) return; editorContainer.style.left = (e.clientX - dragOffset.x) + 'px'; editorContainer.style.top = (e.clientY - dragOffset.y) + 'px'; editorContainer.style.right = 'auto'; editorContainer.style.bottom = 'auto'; } function stopDrag() { isDragging = false; document.removeEventListener('mousemove', handleDrag); document.removeEventListener('mouseup', stopDrag); } // Close and minimize functionality document.getElementById('close-editor').addEventListener('click', () => { editorContainer.remove(); }); document.getElementById('minimize-editor').addEventListener('click', () => { const editorContent = editorContainer.querySelector('div:nth-child(3)'); const toolbar = editorContainer.querySelector('#word-editor-toolbar'); const statusBarElement = editorContainer.querySelector('#word-editor-status-bar'); if (editorContent.style.display === 'none') { editorContent.style.display = 'flex'; toolbar.style.display = 'flex'; statusBarElement.style.display = 'flex'; editorContainer.style.height = '700px'; } else { editorContent.style.display = 'none'; toolbar.style.display = 'none'; statusBarElement.style.display = 'none'; editorContainer.style.height = '50px'; } }); // Toolbar functionality const toolbar = editorContainer.querySelector('#word-editor-toolbar'); // Format buttons toolbar.addEventListener('click', (e) => { const target = e.target.closest('.toolbar-btn'); if (target) { const command = target.dataset.command; if (command) { document.execCommand(command, false, null); updateFormatButtons(); documentElement.focus(); } } }); // Font family and size const fontFamily = document.getElementById('font-family'); const fontSize = document.getElementById('font-size'); fontFamily.addEventListener('change', () => { document.execCommand('fontName', false, fontFamily.value); documentElement.focus(); }); fontSize.addEventListener('change', () => { document.execCommand('fontSize', false, fontSize.value); documentElement.focus(); }); // Color pickers const textColor = document.getElementById('text-color'); const bgColor = document.getElementById('bg-color'); textColor.addEventListener('change', () => { document.execCommand('foreColor', false, textColor.value); documentElement.focus(); }); bgColor.addEventListener('change', () => { document.execCommand('backColor', false, bgColor.value); documentElement.focus(); }); // Special buttons document.getElementById('insert-table').addEventListener('click', () => { const rows = prompt('Number of rows:', '3'); const cols = prompt('Number of columns:', '3'); if (rows && cols) { insertTable(parseInt(rows), parseInt(cols)); } }); document.getElementById('insert-image').addEventListener('click', () => { const url = prompt('Image URL:', 'https://'); if (url && url !== 'https://') { insertImage(url); } }); document.getElementById('insert-link').addEventListener('click', () => { const url = prompt('Link URL:', 'https://'); const text = prompt('Link text:', 'Click here'); if (url && url !== 'https://' && text) { insertLink(url, text); } }); // Save and Load buttons document.getElementById('save-file').addEventListener('click', () => { saveFile(); }); document.getElementById('load-file').addEventListener('click', () => { loadFile(); }); // Update format buttons based on current selection function updateFormatButtons() { const formatButtons = toolbar.querySelectorAll('.format-btn'); formatButtons.forEach(btn => { const command = btn.dataset.command; try { if (document.queryCommandState(command)) { btn.classList.add('active'); } else { btn.classList.remove('active'); } } catch (e) { console.error('Failed to query command state for:', command, e); } }); } // Insert table function function insertTable(rows, cols) { let tableHTML = '<table><tbody>'; for (let i = 0; i < rows; i++) { tableHTML += '<tr>'; for (let j = 0; j < cols; j++) { tableHTML += `<td>Cell</td>`; } tableHTML += '</tr>'; } tableHTML += '</tbody></table><p></p>'; document.execCommand('insertHTML', false, tableHTML); documentElement.focus(); } // Insert image function function insertImage(url) { const imgHTML = `<img src="${url}" alt="Inserted image" style="max-width: 100%; height: auto;"><p></p>`; document.execCommand('insertHTML', false, imgHTML); documentElement.focus(); } // Insert link function function insertLink(url, text) { const linkHTML = `<a href="${url}" target="_blank">${text}</a>`; document.execCommand('insertHTML', false, linkHTML); documentElement.focus(); } // Save file to PC function saveFile() { const content = documentElement.innerHTML; const fileName = 'DrawariaWordOfficeDoc.html'; const blob = new Blob([content], { type: 'text/html' }); const link = document.createElement('a'); link.href = URL.createObjectURL(blob); link.download = fileName; document.body.appendChild(link); link.click(); document.body.removeChild(link); updateStatusInfo('Document saved to PC!'); } // Load file from PC function loadFile() { const input = document.createElement('input'); input.type = 'file'; input.accept = '.html, .txt'; input.addEventListener('change', (e) => { const file = e.target.files[0]; if (file) { const reader = new FileReader(); reader.onload = function(event) { documentElement.innerHTML = event.target.result; updateStats(); updateStatusInfo('Document loaded from PC!'); }; reader.readAsText(file); } }); input.click(); } // Update status bar const updateStats = debounce(() => { const text = documentElement.textContent || documentElement.innerText || ''; const words = text.trim().split(/\s+/).filter(word => word.length > 0).length; const characters = text.length; const statsElement = document.getElementById('document-stats'); if (statsElement) { statsElement.textContent = `Words: ${words} | Characters: ${characters}`; } }, 300); const updateStatusInfo = (message) => { const statusInfo = document.getElementById('status-info'); if (statusInfo) { statusInfo.textContent = message; } }; // Document event listeners documentElement.addEventListener('input', () => { updateStats(); updateStatusInfo('Editing...'); saveDocument(); }); documentElement.addEventListener('keyup', updateFormatButtons); documentElement.addEventListener('mouseup', updateFormatButtons); documentElement.addEventListener('paste', () => { setTimeout(() => { updateStats(); }, 0); }); // Keyboard shortcuts documentElement.addEventListener('keydown', (e) => { if (e.ctrlKey || e.metaKey) { switch (e.key.toLowerCase()) { case 'b': e.preventDefault(); document.execCommand('bold'); updateFormatButtons(); break; case 'i': e.preventDefault(); document.execCommand('italic'); updateFormatButtons(); break; case 'u': e.preventDefault(); document.execCommand('underline'); updateFormatButtons(); break; case 's': e.preventDefault(); saveDocument(); break; } } }); // Save document function (using GM storage) const saveDocument = debounce(async() => { try { if (typeof GM !== 'undefined' && GM.setValue) { const content = documentElement.innerHTML; await GM.setValue('drawaria_word_document', content); updateStatusInfo('Document saved'); } else { updateStatusInfo('Save function not available'); } console.log('Document auto-saved successfully'); setTimeout(() => updateStatusInfo('Ready'), 2000); } catch (error) { console.error('Failed to save document:', error); updateStatusInfo('Save failed!'); } }, 3000); // Auto-save after 3 seconds of inactivity // Load saved document (using GM storage) async function loadDocument() { try { if (typeof GM !== 'undefined' && GM.getValue) { const savedContent = await GM.getValue('drawaria_word_document', null); if (savedContent) { documentElement.innerHTML = savedContent; updateStats(); updateStatusInfo('Saved document loaded'); console.log('Saved document loaded successfully'); } } updateStatusInfo('Ready'); } catch (error) { console.error('Failed to load saved document:', error); updateStatusInfo('Load failed!'); } } // Load saved document on initialization loadDocument(); // Initial stats update updateStats(); updateFormatButtons(); console.log('Word editor fully initialized and ready to use'); } // Function to open the editor function openEditor() { const existingEditor = document.getElementById('word-editor-container'); if (!existingEditor) { const { editorContainer, documentElement, statusBar } = createWordEditor(); document.body.appendChild(editorContainer); initializeEditor(editorContainer, documentElement, statusBar); } else { console.log('Editor is already open.'); } } // Function to close the editor function closeEditor() { const existingEditor = document.getElementById('word-editor-container'); if (existingEditor) { existingEditor.remove(); } else { console.log('Editor is not open.'); } } // Main initialization function function init() { console.log('Drawaria Word Processor starting...'); if (typeof GM_registerMenuCommand === 'undefined') { console.error('GM_registerMenuCommand is not available. Please ensure you are using a compatible userscript manager.'); return; } // Register menu commands GM_registerMenuCommand('📂 Open Word Office', openEditor); GM_registerMenuCommand('❌ Close Word Office', closeEditor); console.log('Drawaria Word Processor initialized successfully! Use the userscript menu to open the editor.'); } // Start the extension init(); })();