// ==UserScript== // @name 画图ai提示词管理器-川味面最好吃 // @namespace https://space.bilibili.com/37440705?spm_id_from=333.788.0.0 // @version 4.5 // @description 网页提示词管理器:支持保存、分类、快速使用提示词。请修改@match那行的网址,如果需要多个网站可以多些几行,现在的设置是每个网站都会显示 // @author B站:川味面最好吃 // @match http://192.168.101.11:8188 // @match *://*/* // @match https://*liblib.art/* // @match https://*civitai.com/* // @grant GM_setValue // @grant GM_getValue // @grant GM_addStyle // ==/UserScript== (function () { 'use strict'; // 添加样式 // 添加 Toast 样式 GM_addStyle(` .prompt-manager-menu, .prompt-manager-modal, .prompt-manager-modal2 { transition: background-color 0.3s ease; } .toast-container { position: fixed; bottom: 40%; left: 50%; transform: translateX(-50%); z-index: 10001; pointer-events: none; } .toast { background: rgba(0, 0, 0, 0.8); color: white; padding: 10px 20px; border-radius: 4px; margin-top: 10px; animation: fadeInOut 3s ease-in-out; } @keyframes fadeIn { from { opacity: 0; transform: translateY(20px); } to { opacity: 1; transform: translateY(0); } } /* 通用颜色变量 - 亮色模式 */ :root { --pm-text-color: #ddd; --pm-border-color: #555; --pm-primary-color: #3a80d2; --pm-primary-hover: #2a70c2; --pm-danger-color: #c73c2e; --pm-secondary-color: #777; --pm-border-light: #444; } /* 深色模式 */ .prompt-manager-dark-mode { --pm-text-color: #ddd; --pm-border-color: #555; --pm-primary-color: #3a80d2; --pm-primary-hover: #2a70c2; --pm-danger-color: #c73c2e; --pm-secondary-color: #777; --pm-border-light: #444; } .prompt-manager-menu { position: fixed; background: var(--pm-bg-color); border: 1px solid var(--pm-border-color); border-radius: 4px; box-shadow: 0 2px 10px rgba(0,0,0,0.1); padding: 8px; z-index: 9999; min-width: 150px; max-height: 400px; color: var(--pm-text-color); } .prompt-manager-toolbar { display: flex; justify-content: space-between; padding-bottom: 8px; margin-bottom: 8px; } .prompt-manager-toolbar button { background: none; border: none; margin:0; cursor: pointer; font-size: 14px; padding: 4px; color: var(--pm-text-color); } .prompt-manager-category { padding: 0px 8px; font-size: 12px; cursor: pointer; margin: 2px 0; color: var(--pm-text-color); } .prompt-manager-category:hover { background: var(--pm-hover-color); border-radius: 4px; } #div1{ position: absolute; top: 0; left: 0; background: var(--pm-bg-color); border: 1px solid #666; } .prompt-manager-modal { padding: 10px; min-height:100% ; z-index: 10000; min-width: 300px; max-width: 520px; color: var(--pm-text-color); display: flex ; flex-direction: column; justify-content: space-between; } .prompt-manager-modal2{ position: fixed; top: 50%; left: 8px; transform: translateY(-50%); background: var(--pm-bg-color); padding: 20px; border-radius: 8px; box-shadow: 0 4px 20px rgba(0,0,0,0.15); z-index: 10000; min-width: 300px; max-width: 520px; color: var(--pm-text-color); } .settings-section { padding-bottom: 5px; border-bottom: 1px solid var(--pm-border-light); } .settings-section:last-child { border-bottom: none; margin-bottom: 15px; } .settings-section h4 { margin: 0 0 10px 0; color: var(--pm-text-color); } .prompt-manager-input { width: 100%; padding: 8px; margin: 8px 0; background:#222; border: 1px solid #ddd; border-radius: 4px; color: var(--pm-text-color); } .prompt-manager-button { padding: 8px 16px; margin: 4px; border: none; border-radius: 4px; background: var(--pm-primary-color); color: white; cursor: pointer; } .prompt-manager-button:hover { background: var(--pm-primary-hover); } .prompt-manager-button.danger { background: var(--pm-danger-color); } .prompt-manager-button.secondary { background: #999; } .prompt-manager-list { max-height: 300px; overflow-y: auto; margin: 10px 0; display: flex; flex-wrap: wrap; } .prompt-manager-list-item { background-color:#222; margin:2px; border-radius: 5px; cursor: pointer; color: var(--pm-text-color); max-width:120px; padding:1px 7px; } .prompt-manager-list-item:hover { background: var(--pm-hover-color); } `); // 数据结构 let data = { categories: [], // [{id: string, name: string, order: number}] prompts: [], // [{id: string, text: string, alias: string, categoryId: string, favorite: boolean, useCount: number, isTemplate: boolean, lastUsed: string}] lastUsedCategoryId: null, // 记录上次使用的分组ID backups: [], // 自动备份历史 [{date: string, data: Object}] settings: { darkMode: false, // 深色模式 modalPosition: null, // 模态框位置 sortBy: 'time', // 排序方式:time(添加时间), name(名称), usage(使用次数) showFavoriteOnly: false, // 是否只显示收藏的提示词 enableContextMenu: true, // 启用右键菜单 autoBackup: true, // 自动备份 backupInterval: 7, // 备份间隔(天) maxBackups: 5, // 最大备份数量 categorySort: 'custom', // 分类排序方式:custom(自定义), name(名称) panelOpacity: 0.9 // 面板透明度,默认90% } }; // 初始化数据 function initData() { const savedData = GM_getValue('promptManagerData'); if (savedData) { try { data = JSON.parse(savedData); // 兼容旧版本数据结构 if (!data.settings) { data.settings = { darkMode: false, modalPosition: null, sortBy: 'time', showFavoriteOnly: false, enableContextMenu: true, autoBackup: true, backupInterval: 7 }; } if (!data.backups) { data.backups = []; } // 检查是否需要创建备份 checkBackup(); } catch (e) { console.error('数据解析错误', e); // 尝试恢复最近的备份 tryRestore(); } } } // 保存数据 function saveData() { try { GM_setValue('promptManagerData', JSON.stringify(data)); } catch (e) { console.error('保存数据失败', e); alert('保存数据失败,请检查浏览器存储空间或导出备份数据'); } } // 检查是否需要创建备份 function checkBackup() { if (!data.settings.autoBackup) return; const now = new Date(); const lastBackup = data.backups[0]?.date ? new Date(data.backups[0].date) : null; // 如果没有备份或最后一次备份超过指定天数 if (!lastBackup || (now - lastBackup) / (1000 * 60 * 60 * 24) > data.settings.backupInterval) { // 创建备份,不包含之前的备份数据 const backupData = JSON.parse(JSON.stringify(data)); delete backupData.backups; // 添加新备份到开头 data.backups.unshift({ date: now.toISOString(), data: backupData }); // 保留最多5个备份 if (data.backups.length > 5) { data.backups = data.backups.slice(0, 5); } saveData(); } } // 尝试从备份恢复 function tryRestore() { const savedBackups = GM_getValue('promptManagerBackups'); if (savedBackups) { try { const backups = JSON.parse(savedBackups); if (backups.length > 0) { // 使用最新的备份 data = backups[0].data; alert('检测到数据损坏,已自动从最近备份恢复'); return; } } catch (e) { console.error('备份解析错误', e); } } // 如果没有可用备份,重置数据 data = { categories: [], prompts: [], lastUsedCategoryId: null, backups: [], settings: { darkMode: false, modalPosition: null, sortBy: 'time', showFavoriteOnly: false, enableContextMenu: true, autoBackup: true, backupInterval: 7 } }; alert('无法恢复数据,已重置为默认设置'); } // 初始化数据 // = GM_getValue('promptManagerData'); // 显示提示信息 function showToast(message, duration = 3000) { let container = document.querySelector('.toast-container'); if (!container) { container = document.createElement('div'); container.className = 'toast-container'; document.body.appendChild(container); } const toast = document.createElement('div'); toast.className = 'toast'; toast.innerHTML = message; container.appendChild(toast); setTimeout(() => { toast.remove(); if (container.children.length === 0) { container.remove(); } }, duration); } // 创建浮动菜单 function createFloatingMenu(x, y) { GM_addStyle(` .prompt-manager-menu, .prompt-manager-modal, .prompt-manager-modal2 { background-color: rgba(51, 51, 51, ${data.settings.panelOpacity}); } `) const menu = document.createElement('div'); menu.className = 'prompt-manager-menu'; menu.style.left = x + 'px'; menu.style.top = y + 'px'; console.log(x); const div1 = document.createElement('div'); div1.style.borderRadius = '8px 0 0 8px'; div1.style.transform = 'translateX(-100%)'; div1.style.borderRight = '0'; div1.style.minHeight = '100%'; menu.appendChild(div1); const div2 = document.createElement('div'); menu.appendChild(div2); div2.id = 'div2'; const div3 = document.createElement('div'); div3.style.borderRadius = '0px 8px 8px 0'; div3.style.borderLeft = '0'; menu.appendChild(div3); div3.style.transform = 'translateX(148px) translateY(100px)'; div3.style.minHeight = 'calc(100% - 100px)'; if (x > 400) { div1.id = 'div1'; } else { div3.id = 'div1'; } // 工具栏 const toolbar = document.createElement('div'); toolbar.className = 'prompt-manager-toolbar'; makeDraggable(menu); const settingsBtn = document.createElement('button'); settingsBtn.innerHTML = '⚙️'; settingsBtn.onclick = showSettings; const 空格 = document.createElement('button'); 空格.innerHTML = '🈳'; 空格.className = 'prompt-space' 空格.onclick = 替换空格; //添加鼠标浮动提示 空格.title = '替换空格为_'; 空格.onmouseover = function () { //提示信息 showToast('替换空格为_',1000); } const 浏览器 = document.createElement('button'); 浏览器.innerHTML = '🛜'; 浏览器.className = 'prompt-space' 浏览器.onclick = 显示浏览器面板; //添加鼠标浮动提示 浏览器.title = '开启内置浏览器,需要安装hiframe插件'; 浏览器.onmouseover = function () { //提示信息 showToast('开启内置浏览器,需要安装hiframe插件',1000); } const addCategoryBtn = document.createElement('button'); addCategoryBtn.innerHTML = '+🗂️'; addCategoryBtn.onclick = () => showAddCategoryDialog(); addCategoryBtn.onmouseover = function () { //提示信息 showToast('新建分组',1000); } toolbar.appendChild(settingsBtn); toolbar.appendChild(空格); toolbar.appendChild(浏览器); toolbar.appendChild(addCategoryBtn); div2.appendChild(toolbar); // 分类列表 data.categories.forEach(category => { const categoryDiv = document.createElement('div'); categoryDiv.className = 'prompt-manager-category'; categoryDiv.textContent = category.name; categoryDiv.onclick = () => showPromptList(category.id); div2.appendChild(categoryDiv); }); document.body.appendChild(menu); return menu; } // 显示添加分类对话框 function showAddCategoryDialog() { const modal = createModal2()//create浮动Modal(); modal.innerHTML = `

新建分类

`; makeDraggable(modal); const input = modal.querySelector('input'); const [confirmBtn, cancelBtn] = modal.querySelectorAll('button'); confirmBtn.onclick = () => { if (input.value.trim()) { const newCategory = { id: Date.now().toString(), name: input.value.trim() }; data.categories.push(newCategory); saveData(); closeModal(); // 刷新菜单 const oldMenu = document.querySelector('.prompt-manager-menu'); if (oldMenu) { const rect = oldMenu.getBoundingClientRect(); oldMenu.remove(); createFloatingMenu(rect.left, rect.top); } } }; cancelBtn.onclick = closeModal; } // 显示提示词列表 function showPromptList(categoryId) { try { document.getElementsByClassName('prompt-manager-modal')[0].remove(); } catch (e) { } console.log(document.getElementById('div1').innerHTML) const prompts = data.prompts.filter(p => p.categoryId === categoryId); const category = data.categories.find(c => c.id === categoryId); const modal = createModal(); modal.innerHTML = `

${category.name}

${prompts.map(prompt => `
${prompt.alias || prompt.text}
`).join('')}
`; // 添加CSS样式 const style = document.createElement('style'); style.textContent = ` .prompt-manager-list-item { display: flex; flex-wrap: wrap; flex-direction: row; justify-content: space-between; align-items: center; position: relative; padding-left: 5px; } .prompt-text { flex: 1; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; user-select: none; } .prompt-favorite { background: none; border: none; cursor: pointer; font-size: 16px; color: gold; } .prompt-checkbox { position: absolute; left: 5px; width: 16px; height: 16px; cursor: pointer; opacity: 0; } .prompt-checkbox-custom { position: absolute; left: 5px; width: 16px; height: 16px; border: 2px solid var(--pm-text-color); border-radius: 3px; pointer-events: none; } .prompt-checkbox:checked + .prompt-checkbox-custom::after { content: '✓'; position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); color: var(--pm-primary-color); } .prompt-manager-list-item.selected { background-color: rgba(74, 144, 226, 0.1); } .batch-actions { display: none; margin-bottom: 10px; gap: 8px; flex-wrap: wrap; } .batch-actions.visible { display: flex; } /* 操作提示和反馈 */ @keyframes fadeInOut { 0% { opacity: 0; transform: translateY(20px); } 10% { opacity: 1; transform: translateY(0); } 90% { opacity: 1; transform: translateY(0); } 100% { opacity: 0; transform: translateY(-20px); } } .prompt-actions { opacity: 0.3; transition: opacity 0.2s; } .prompt-manager-list-item:hover .prompt-actions { opacity: 1; } .prompt-delete, .prompt-edit { background: none; border: none; cursor: pointer; font-size: 10px; } .prompt-manager-list-item.active { background-color: rgba(74, 144, 226, 0.1); } .empty-list-message { padding: 20px; text-align: center; color: #999; } .prompt-toolbar { display: flex; gap: 8px; } .toolbar-btn { background: none; border: none; cursor: pointer; padding: 4px 8px; font-size: 16px; color: var(--pm-text-color); border-radius: 4px; } .toolbar-btn:hover { background: var(--pm-hover-color); } .search-bar { position: relative; } `; document.head.appendChild(style); // 排序函数 const sortPrompts = (items) => { return Array.from(items).sort((a, b) => { const aPrompt = data.prompts.find(p => p.id === a.dataset.id); const bPrompt = data.prompts.find(p => p.id === b.dataset.id); if (!aPrompt || !bPrompt) return 0; switch (data.settings.sortBy) { case 'name': return (aPrompt.alias || aPrompt.text).localeCompare(bPrompt.alias || bPrompt.text); case 'usage': return (bPrompt.useCount || 0) - (aPrompt.useCount || 0); default: // 'time' return bPrompt.id.localeCompare(aPrompt.id); } }); }; // 提示词点击事件 const items = modal.querySelectorAll('.prompt-manager-list-item'); items.forEach(item => { // 提示词文本点击事件 const textSpan = item.querySelector('.prompt-text'); textSpan.onclick = (e) => { e.stopPropagation(); // 阻止事件冒泡 const promptId = item.dataset.id; const prompt = data.prompts.find(p => p.id === promptId); if (!prompt) { alert('提示词数据已损坏,请尝试刷新页面'); return; } let text = prompt.text; // 如果是模板,处理变量替换 if (prompt.isTemplate) { // 提取所有变量 const variables = []; const regex = /\{\{([^}]+)\}\}/g; let match; while ((match = regex.exec(text)) !== null) { if (!variables.includes(match[1])) { variables.push(match[1]); } } // 如果有变量,提示用户输入 if (variables.length > 0) { // 收集变量值 const values = {}; for (const variable of variables) { const value = prompt(`请输入"${variable}"的值:`); if (value === null) { // 用户取消了输入 return; } values[variable] = value; } // 替换所有变量 for (const [variable, value] of Object.entries(values)) { const regex = new RegExp(`\\{\\{${variable}\\}\\}`, 'g'); text = text.replace(regex, value); } } } // 检查文本结尾是否是逗号,如果不是则添加逗号 if (!text.endsWith(',')) { text += ','; } // 记录最近聚焦的输入元素 let targetInput = window.lastFocusedInput; // 如果没有记录或记录的元素不再有效,则尝试查找页面上可见的输入框 if (!targetInput || !document.body.contains(targetInput)) { // 查找页面上所有的输入框和文本框 const inputs = document.querySelectorAll('input[type="text"], textarea'); targetInput = Array.from(inputs).find(input => { // 检查元素是否可见且可编辑 const style = window.getComputedStyle(input); const rect = input.getBoundingClientRect(); return style.display !== 'none' && !input.readOnly && !input.disabled && rect.width > 0 && rect.height > 0; }); } if (targetInput) { // 将文本插入到输入框 targetInput.focus(); const start = targetInput.selectionStart || 0; const end = targetInput.selectionEnd || 0; targetInput.value = targetInput.value.substring(0, start) + text + targetInput.value.substring(end); targetInput.setSelectionRange(start + text.length, start + text.length); // 触发输入事件,确保动态网页能检测到内容变化 const inputEvent = new Event('input', { bubbles: true }); targetInput.dispatchEvent(inputEvent); // 更新使用次数 const promptId = item.dataset.id; const promptIndex = data.prompts.findIndex(p => p.id === promptId); if (promptIndex !== -1) { data.prompts[promptIndex].useCount = (data.prompts[promptIndex].useCount || 0) + 1; saveData(); } } //closeModal(); }; //给prompt-edit添加动作,修改提示词 const editBtn = item.querySelector('.prompt-edit'); editBtn.onclick = (e) => { //e.stopPropagation(); console.log('editBtn clicked'); const promptId = item.dataset.id; const prompt = data.prompts.find(p => p.id === promptId); if (prompt) { showEditPromptDialog(promptId, prompt.text, prompt.alias, prompt.categoryId); } } // 删除按钮点击事件 const deleteBtn = item.querySelector('.prompt-delete'); deleteBtn.onclick = (e) => { e.stopPropagation(); const promptId = item.dataset.id; if (confirm('确定要删除这个提示词吗?')) { try { data.prompts = data.prompts.filter(p => p.id !== promptId); saveData(); item.remove(); // 检查列表是否为空 const listItems = modal.querySelectorAll('.prompt-manager-list-item:not([style*="display: none"])'); const listContainer = modal.querySelector('.prompt-manager-list'); if (listItems.length === 0) { const message = data.settings.showFavoriteOnly ? '没有收藏的提示词' : '没有提示词'; listContainer.innerHTML = `
${message}
`; } showToast('提示词已删除'); } catch (error) { console.error('删除提示词失败', error); showToast('删除失败,请重试'); } } }; }); // 工具栏按钮 const shareCategoryBtn = modal.querySelector('#share-category'); const [editCategoryBtn, edititem, closeBtn] = modal.querySelectorAll('.prompt-manager-toolbar button'); // 分享分类按钮点击事件 shareCategoryBtn.onclick = () => { const category = data.categories.find(c => c.id === categoryId); if (!category) return; const prompts = data.prompts.filter(p => p.categoryId === categoryId); if (prompts.length === 0) { showToast('当前分类没有提示词可分享'); return; } const shareModal = createModal2()//create浮动Modal(); shareModal.innerHTML = `

分享分类:${category.name}

`; makeDraggable(shareModal); const formatSelect = shareModal.querySelector('#share-format'); const previewArea = shareModal.querySelector('textarea'); const copyBtn = shareModal.querySelector('#copy-share'); const downloadBtn = shareModal.querySelector('#download-share'); const closeShareBtn = shareModal.querySelector('.prompt-manager-button.secondary'); // 生成分享内容 const generateContent = (format) => { switch (format) { case 'text': return prompts.map(p => { const text = p.text.replace(/\n/g, ' '); return p.alias ? `${text}|${p.alias}` : text; }).join('\n'); case 'markdown': return `# ${category.name}\n\n` + prompts.map(p => { const text = p.text.replace(/\n/g, ' '); return `- ${p.alias ? `**${p.alias}**: ` : ''}${text}`; }).join('\n'); case 'json': return JSON.stringify({ category: category.name, prompts: prompts.map(p => ({ text: p.text, alias: p.alias || null })) }, null, 2); } }; // 更新预览 const updatePreview = () => { previewArea.value = generateContent(formatSelect.value); }; formatSelect.onchange = updatePreview; updatePreview(); // 复制内容 copyBtn.onclick = async () => { try { await navigator.clipboard.writeText(previewArea.value); showToast('内容已复制到剪贴板'); } catch (error) { console.error('复制失败', error); // 降级方案 previewArea.select(); document.execCommand('copy'); showToast('内容已复制到剪贴板'); } }; // 下载文件 downloadBtn.onclick = () => { const format = formatSelect.value; const content = generateContent(format); const blob = new Blob([content], { type: format === 'json' ? 'application/json' : 'text/plain' }); const url = URL.createObjectURL(blob); const a = document.createElement('a'); a.href = url; a.download = `prompts-${category.name}.${format === 'markdown' ? 'md' : format}`; a.click(); URL.revokeObjectURL(url); showToast('文件已开始下载'); }; closeShareBtn.onclick = () => closeModal(shareModal); }; edititem.onclick = () => { showx() } //showx() function showx() { const categories = document.querySelectorAll('.prompt-actions .prompt-delete') for (let i = 0; i < categories.length; i++) { if (categories[i].style.display != "none") { categories[i].style.display = "none"; categories[i].parentNode.style.paddingRight = "7px"; categories[i].parentNode.style.paddingLeft = "7px"; } else { categories[i].style.display = "block" categories[i].parentNode.style.paddingRight = "0px"; categories[i].parentNode.style.paddingLeft = "0px"; } } const categories2 = document.querySelectorAll('.prompt-actions .prompt-edit') for (let i = 0; i < categories2.length; i++) { if (categories2[i].style.display != "none") { categories2[i].style.display = "none"; categories2[i].parentNode.style.paddingRight = "7px"; categories2[i].parentNode.style.paddingLeft = "7px"; } else { categories2[i].style.display = "block" categories2[i].parentNode.style.paddingRight = "0px"; categories2[i].parentNode.style.paddingLeft = "0px"; } } } editCategoryBtn.onclick = () => { showEditCategoryDialog(categoryId); }; //closeBtn.onclick = closeModal; } function 替换空格() { let targetInput = window.lastFocusedInput || document.activeElement; if (targetInput && (targetInput.tagName === 'INPUT' || targetInput.tagName === 'TEXTAREA')) { // 获取文本框的当前值 const originalText = targetInput.value; // 替换空格为下划线,但空格前不是逗号或句号的情况 const replacedText = originalText.replace(/(?设置

导入导出

每行一个提示词,如果有简称以"|"分隔。每次请只添加一个分组的,因为添加后所有的都会被分到同一个分组

其他操作

反馈bug 更新记录
使用帮助
1、点击"+🗂️"可以添加分组
2、在页面中划词可以添加提示词
3、点击提示词可以填入到编辑框里
4、点击🈳可以替换掉所有空格为"_"
5、点击🛜开启页面内浏览器,可以临时打开翻译网站,需要安装Hiframe插件
`; makeDraggable(modal); const closeBtn1 = modal.querySelector('.prompt-manager-button.secondary'); closeBtn1.onclick = closeModal; console.log(data.settings.panelOpacity) document.getElementById('opacity-slider')?.addEventListener('input', function(e) { console.log(e.target.value) const opacity = e.target.value / 100; data.settings.panelOpacity = opacity; saveData(); // 更新所有面板的背景色透明度 document.querySelectorAll('.prompt-manager-menu, .prompt-manager-modal, .prompt-manager-modal2').forEach(el => { const currentBg = window.getComputedStyle(el).backgroundColor; const newBg = currentBg.replace(/rgba?\((\d+),\s*(\d+),\s*(\d+)(?:,\s*[\d.]+)?\)/, `rgba($1, $2, $3, ${opacity})`); el.style.backgroundColor = newBg; }); // 更新标签显示 e.target.previousElementSibling.textContent = `面板透明度: ${e.target.value}%`; }); const exportJsonBtn = modal.querySelector('#export-json'); const exportTxtBtn = modal.querySelector('#export-txt'); const [, importBtn, batchImportBtn, helpBtn, clearBtn, closeBtn] = modal.querySelectorAll('.prompt-manager-button'); const fileInput = modal.querySelector('#import-file'); const batchFileInput = modal.querySelector('#batch-import-file'); // 导出仅包含prompts数组的JSON数据 exportJsonBtn.onclick = () => { const exportData = { categories: data.categories, prompts: data.prompts }; const blob = new Blob([JSON.stringify(data, null, 2)], { type: 'application/json' }); //const blob = new Blob([JSON.stringify(exportData, null, 2)], { type: 'application/json' }); const url = URL.createObjectURL(blob); const a = document.createElement('a'); a.href = url; a.download = 'prompt-manager-data.json'; a.click(); URL.revokeObjectURL(url); }; importBtn.onclick = () => fileInput.click(); // 批量导入按钮 batchImportBtn.onclick = () => showBatchImportDialog()//batchFileInput.click(); // 批量导入文件处理 batchFileInput.onchange = async () => { const file = batchFileInput.files[0]; if (file) { try { const text = await file.text(); showBatchImportDialog(text); } catch (e) { alert('文件读取失败'); } } }; fileInput.onchange = async () => { const file = fileInput.files[0]; if (file) { try { const text = await file.text(); const importedData = JSON.parse(text); if (importedData.categories && importedData.prompts) { // 保留lastUsedCategoryId或使用导入数据中的值 const currentLastUsedCategory = data.lastUsedCategoryId; data = importedData; // 如果导入的数据没有lastUsedCategoryId,保留当前的值 if (!data.lastUsedCategoryId && currentLastUsedCategory) { data.lastUsedCategoryId = currentLastUsedCategory; } saveData(); alert('数据导入成功!'); closeModal(); } } catch (e) { alert('导入失败:无效的数据格式'); } } }; clearBtn.onclick = () => { if (confirm('确定要清空所有数据吗?此操作不可恢复!')) { data = { categories: [], prompts: [], lastUsedCategoryId: null }; saveData(); closeModal(); } }; //closeBtn.onclick = closeModal; } // 显示保存提示词对话框 function showSavePromptDialog(text) { const modal = createModal2(); modal.innerHTML = `

保存提示词

`; // 防止点击事件冒泡 modal.addEventListener('click', (e) => { e.stopPropagation(); }); // 添加拖拽功能 makeDraggable(modal); const aliasInput = modal.querySelector('input'); const categorySelect = modal.querySelector('select'); const [saveBtn, cancelBtn] = modal.querySelectorAll('button'); saveBtn.onclick = () => { const categoryId = categorySelect.value; if (!categoryId) { alert('请选择分类!'); return; } const textArea = modal.querySelector('textarea'); const isTemplateCheckbox = modal.querySelector('#is-template') || { checked: false }; const newPrompt = { id: Date.now().toString(), text: textArea.value.trim(), alias: aliasInput.value.trim(), categoryId: categoryId, favorite: false, useCount: 0, isTemplate: isTemplateCheckbox.checked }; // 保存提示词的同时记录最后使用的分组ID data.lastUsedCategoryId = categoryId; data.prompts.push(newPrompt); saveData(); closeModal(); //提示信息 showToast('新建成功',1000); }; // 如果有上次使用的分组,自动选中 if (data.lastUsedCategoryId) { const option = categorySelect.querySelector(`option[value="${data.lastUsedCategoryId}"]`); if (option) { categorySelect.value = data.lastUsedCategoryId; } else { // 如果找不到对应的分类(可能已被删除),清除记录 data.lastUsedCategoryId = null; saveData(); } } cancelBtn.onclick = closeModal; } // 显示批量导入对话框 function showBatchImportDialog(text) { const modal = createModal2()//create浮动Modal(); modal.innerHTML = `

批量导入提示词

每行一个提示词,格式:提示词文本|别名(可选)。导入后需要刷新

`; makeDraggable(modal); const textArea = modal.querySelector('textarea'); const categorySelect = modal.querySelector('select'); const [importBtn, cancelBtn] = modal.querySelectorAll('button'); // 如果有上次使用的分组,自动选中 if (data.lastUsedCategoryId) { categorySelect.value = data.lastUsedCategoryId; } importBtn.onclick = () => { const categoryId = categorySelect.value; if (!categoryId) { alert('请选择分类!'); return; } const lines = textArea.value.split('\n').filter(line => line.trim()); if (lines.length === 0) { alert('没有找到有效的提示词'); return; } let importCount = 0; lines.forEach(line => { const parts = line.split('|'); const text = parts[0].trim(); const alias = parts.length > 1 ? parts[1].trim() : ''; if (text) { const newPrompt = { id: Date.now().toString() + importCount, text: text, alias: alias, categoryId: categoryId, favorite: false }; data.prompts.push(newPrompt); importCount++; } }); if (importCount > 0) { data.lastUsedCategoryId = categoryId; saveData(); alert(`成功导入 ${importCount} 个提示词`); closeModal(); } else { alert('没有找到有效的提示词'); } }; cancelBtn.onclick = closeModal; } // 创建模态框 function createModal() { const modal = document.createElement('div'); modal.className = 'prompt-manager-modal'; // 添加拖拽功能 makeDraggable(modal); const menu = document.querySelector('#div1').appendChild(modal); return modal; } function create浮动Modal() { const modal = document.createElement('div'); modal.className = 'prompt-manager-modal2 浮动'; // 如果有保存的位置,使用保存的位置 // if (data.settings?.modalPosition) { modal.style.left = '20%'; modal.style.top = '20%'; modal.style.transform = 'none'; //}*/ // 添加拖拽功能 makeDraggable(modal); //const menu = document.querySelector('#div1').appendChild(modal); document.body.appendChild(modal); return modal; } function createModal2() { const modal = document.createElement('div'); modal.className = 'prompt-manager-modal2 浮动modal2'; // 如果有保存的位置,使用保存的位置 if (data.settings?.modalPosition) { modal.style.left = data.settings.modalPosition.left + 'px'; modal.style.top = data.settings.modalPosition.top + 'px'; modal.style.transform = 'none'; } makeDraggable(modal); //const menu = document.querySelector('#div1').appendChild(modal); document.body.appendChild(modal); return modal; } // 使元素可拖拽 function makeDraggable(element) { let isDragging = false; let offsetX, offsetY; // 创建拖拽手柄 const dragHandle = document.createElement('div'); dragHandle.style.cssText = ` position: absolute; top: 0; left: 0; right: 0; height: 10px; cursor: move; background-color: rgb(87 122 77 / 64%); `; element.appendChild(dragHandle); //console.log(dragHandle); // 鼠标按下事件 dragHandle.addEventListener('mousedown', (e) => { isDragging = true; // 获取鼠标在元素内的相对位置 const rect = element.getBoundingClientRect(); offsetX = e.clientX - rect.left; offsetY = e.clientY - rect.top; // 阻止默认行为和冒泡 e.preventDefault(); e.stopPropagation(); }); // 鼠标移动事件 document.addEventListener('mousemove', (e) => { if (!isDragging) return; // 计算新位置 const x = e.clientX - offsetX; const y = e.clientY - offsetY; // 应用新位置 element.style.left = x + 'px'; element.style.top = y + 'px'; element.style.transform = 'none'; // 保存位置到设置 data.settings.modalPosition = { left: x, top: y }; }); // 鼠标释放事件 document.addEventListener('mouseup', () => { if (isDragging) { isDragging = false; saveData(); } }); } // 关闭模态框 function closeModal() { const modal = document.querySelector('.prompt-manager-modal'); const modal2 = document.querySelector('.prompt-manager-modal2'); if (modal) modal.remove(); if (modal2) modal2.remove(); } function closeModal2() { const modal = document.querySelector('.prompt-manager-modal2'); if (modal) modal.remove(); } // 点击页面任意位置关闭模态框(使用捕获阶段) document.addEventListener('click', (e) => { const modal = document.querySelector('.prompt-manager-modal2'); if (modal && !e.target.closest('.prompt-manager-modal2')) { closeModal2(); } }, true); // 显示编辑提示词对话框 function showEditPromptDialog(promptId, text, alias, categoryId) { console.log(promptId, text, alias, categoryId); const modal = createModal2(); modal.innerHTML = `

编辑提示词

`; makeDraggable(modal); // 防止点击事件冒泡 modal.addEventListener('click', (e) => { e.stopPropagation(); }); const textArea = modal.querySelector('textarea'); const aliasInput = modal.querySelector('input[type="text"]'); const isTemplateCheckbox = modal.querySelector('#is-template') || { checked: false }; //const templateHelp = modal.querySelector('.template-help'); const categorySelect = modal.querySelector('select'); const [saveBtn, cancelBtn] = modal.querySelectorAll('button'); // 模板帮助提示 //templateHelp.onclick = () => { // alert('模板支持使用变量占位符,格式为 {{变量名}}。\n\n使用时会提示输入变量值,自动替换占位符。\n\n例如:\n"你好,我是{{名字}},我来自{{地点}}。"\n\n使用时会提示输入"名字"和"地点"的值。'); //}; saveBtn.onclick = () => { const newCategoryId = categorySelect.value; if (!newCategoryId) { alert('请选择分类!'); return; } const newText = textArea.value; if (!newText.trim()) { alert('提示词内容不能为空!'); return; } // 更新提示词 const promptIndex = data.prompts.findIndex(p => p.id === promptId); if (promptIndex !== -1) { data.prompts[promptIndex] = { ...data.prompts[promptIndex], text: newText, alias: aliasInput.value.trim(), categoryId: newCategoryId }; saveData(); closeModal(); // 如果分类改变了,需要刷新提示词列表 if (newCategoryId !== categoryId) { showPromptList(newCategoryId); } else { showPromptList(categoryId); } } }; cancelBtn.onclick = closeModal; } // 显示编辑分类对话框 function showEditCategoryDialog(categoryId) { const category = data.categories.find(c => c.id === categoryId); if (!category) return; const modal = createModal2()//create浮动Modal(); modal.innerHTML = `

编辑分类

`; makeDraggable(modal); const nameInput = modal.querySelector('input'); const [saveBtn, deleteBtn, cancelBtn] = modal.querySelectorAll('button'); saveBtn.onclick = () => { const newName = nameInput.value.trim(); if (newName) { category.name = newName; saveData(); closeModal(); // 刷新分类列表 showPromptList(categoryId); } else { alert('分类名称不能为空'); } }; deleteBtn.onclick = () => { if (confirm(`确定要删除分类"${category.name}"吗?该分类下的所有提示词也将被删除!`)) { // 删除该分类下的所有提示词 data.prompts = data.prompts.filter(p => p.categoryId !== categoryId); // 删除分类 data.categories = data.categories.filter(c => c.id !== categoryId); // 如果删除的是上次使用的分类,清除记录 if (data.lastUsedCategoryId === categoryId) { data.lastUsedCategoryId = null; } saveData(); closeModal(); // 刷新菜单 const menu = document.querySelector('.prompt-manager-menu'); if (menu) { const rect = menu.getBoundingClientRect(); menu.remove(); createFloatingMenu(rect.left, rect.top); } } }; cancelBtn.onclick = closeModal; } // 初始化 initData(); // 记录最近聚焦的输入元素 window.lastFocusedInput = null; document.addEventListener('focusin', (e) => { if (e.target.tagName === 'INPUT' || e.target.tagName === 'TEXTAREA') { window.lastFocusedInput = e.target; } }); // 监听文本框点击 document.addEventListener('click', (e) => { const target = e.target; if (target.tagName === 'INPUT' || target.tagName === 'TEXTAREA') { const menu = document.querySelector('.prompt-manager-menu'); if (menu) menu.remove(); const rect = target.getBoundingClientRect(); createFloatingMenu(rect.left - 170, rect.top); } else if (!e.target.closest('.prompt-manager-menu') && !e.target.closest('.prompt-manager-modal')) { const menu = document.querySelector('.prompt-manager-menu'); if (menu) menu.remove(); } }); // 监听选中文本 document.addEventListener('mouseup', (e) => { // 检查是否在模态框内,如果是则不处理 if (e.target.closest('.prompt-manager-modal') || e.target.closest('.prompt-manager-menu') || e.target.closest('.prompt-manager-modal2')) { return; } const selection = window.getSelection(); const text = selection.toString().trim(); // 如果有选中的文本,则显示保存对话框 if (text) { // 延迟显示保存对话框,避免与其他点击事件冲突 setTimeout(() => { const menu = document.querySelector('.prompt-manager-menu'); if (menu) menu.remove(); showSavePromptDialog(text); }, 100); } }); //_____________________________ // 创建主浮动按钮 const floatBtn = document.createElement('div'); floatBtn.innerHTML = '🌐'; floatBtn.style.display = 'none'; floatBtn.style.position = 'fixed'; floatBtn.style.left = '10px'; floatBtn.style.top = '0px'; floatBtn.style.zIndex = '9999'; floatBtn.style.width = '23px'; floatBtn.style.height = '23px'; floatBtn.style.borderRadius = '50%'; floatBtn.style.backgroundColor = '#4285f4'; floatBtn.style.color = 'white'; floatBtn.style.justifyContent = 'center'; floatBtn.style.alignItems = 'center'; floatBtn.style.cursor = 'pointer'; floatBtn.style.boxShadow = '0 2px 10px rgba(0,0,0,0.2)'; document.body.appendChild(floatBtn); // 创建浮动窗口容器 const floatWindow = document.createElement('div'); floatWindow.style.display = 'none'; floatWindow.style.position = 'fixed'; floatWindow.style.zIndex = '9998'; floatWindow.style.width = '300px'; floatWindow.style.height = '400px'; floatWindow.style.top = '50px'; floatWindow.style.left = '100px'; floatWindow.style.backgroundColor = 'white'; floatWindow.style.borderRadius = '8px'; floatWindow.style.boxShadow = '0 4px 20px rgba(0,0,0,0.15)'; floatWindow.style.overflow = 'hidden'; document.body.appendChild(floatWindow); // 创建标题栏 const titleBar = document.createElement('div'); titleBar.style.height = '40px'; titleBar.style.backgroundColor = '#4285f4'; titleBar.style.color = 'white'; titleBar.style.display = 'flex'; titleBar.style.alignItems = 'center'; titleBar.style.padding = '0 10px'; titleBar.style.cursor = 'move'; floatWindow.appendChild(titleBar); // 标题栏文本 const titleText = document.createElement('div'); titleText.textContent = '网页控制器'; titleText.style.flexGrow = '1'; titleBar.appendChild(titleText); // 创建控制按钮容器 const controls = document.createElement('div'); controls.style.display = 'flex'; controls.style.gap = '5px'; titleBar.appendChild(controls); // 最大化按钮 const maxBtn = document.createElement('button'); maxBtn.textContent = '最大化'; maxBtn.style.padding = '2px 8px'; maxBtn.style.border = 'none'; maxBtn.style.borderRadius = '4px'; maxBtn.style.cursor = 'pointer'; controls.appendChild(maxBtn); // 恢复按钮 const restoreBtn = document.createElement('button'); restoreBtn.textContent = '恢复'; restoreBtn.style.padding = '2px 8px'; restoreBtn.style.border = 'none'; restoreBtn.style.borderRadius = '4px'; restoreBtn.style.cursor = 'pointer'; restoreBtn.style.display = 'none'; // 默认隐藏 controls.appendChild(restoreBtn); // 右侧布局按钮 const rightLayoutBtn = document.createElement('button'); rightLayoutBtn.textContent = '➡️'; rightLayoutBtn.style.padding = '2px 8px'; rightLayoutBtn.style.border = 'none'; rightLayoutBtn.style.borderRadius = '4px'; rightLayoutBtn.style.cursor = 'pointer'; controls.appendChild(rightLayoutBtn); // 左侧布局按钮 const leftLayoutBtn = document.createElement('button'); leftLayoutBtn.textContent = '⬅️'; leftLayoutBtn.style.padding = '2px 8px'; leftLayoutBtn.style.border = 'none'; leftLayoutBtn.style.borderRadius = '4px'; leftLayoutBtn.style.cursor = 'pointer'; leftLayoutBtn.style.display = 'none'; controls.appendChild(leftLayoutBtn); // 布局按钮点击事件 rightLayoutBtn.addEventListener('click', () => { // 右侧布局 floatWindow.style.width = '40%'; floatWindow.style.height = '90%'; floatWindow.style.left = 'calc(60% - 50px)'; floatWindow.style.top = '5%'; rightLayoutBtn.style.display = 'none'; leftLayoutBtn.style.display = 'inline-block'; }); leftLayoutBtn.addEventListener('click', () => { // 左侧布局 floatWindow.style.width = '40%'; floatWindow.style.height = '90%'; floatWindow.style.left = '50px'; floatWindow.style.top = '5%'; leftLayoutBtn.style.display = 'none'; rightLayoutBtn.style.display = 'inline-block'; }); // 关闭按钮 const closeBtn = document.createElement('button'); closeBtn.textContent = '×'; closeBtn.style.padding = '2px 8px'; closeBtn.style.border = 'none'; closeBtn.style.borderRadius = '4px'; closeBtn.style.cursor = 'pointer'; controls.appendChild(closeBtn); // 创建URL输入框容器 const urlContainer = document.createElement('div'); urlContainer.style.padding = '10px'; urlContainer.style.display = 'flex'; urlContainer.style.gap = '5px'; floatWindow.appendChild(urlContainer); // 添加预设翻译按钮 const sogouBtn = document.createElement('button'); sogouBtn.textContent = '狗'; sogouBtn.style.padding = '5px 10px'; sogouBtn.style.border = 'none'; sogouBtn.style.borderRadius = '4px'; sogouBtn.style.backgroundColor = '#34a853'; sogouBtn.style.color = 'white'; sogouBtn.style.cursor = 'pointer'; sogouBtn.title = '搜狗翻译'; urlContainer.appendChild(sogouBtn); const baiduBtn = document.createElement('button'); baiduBtn.textContent = '百'; baiduBtn.style.padding = '5px 10px'; baiduBtn.style.border = 'none'; baiduBtn.style.borderRadius = '4px'; baiduBtn.style.backgroundColor = '#4285f4'; baiduBtn.style.color = 'white'; baiduBtn.style.cursor = 'pointer'; baiduBtn.title = '百度翻译'; urlContainer.appendChild(baiduBtn); const youdaoBtn = document.createElement('button'); youdaoBtn.textContent = '有'; youdaoBtn.style.padding = '5px 10px'; youdaoBtn.style.border = 'none'; youdaoBtn.style.borderRadius = '4px'; youdaoBtn.style.backgroundColor = '#fbbc05'; youdaoBtn.style.color = 'white'; youdaoBtn.style.cursor = 'pointer'; youdaoBtn.title = '有道翻译'; urlContainer.appendChild(youdaoBtn); // URL输入框 const urlInput = document.createElement('input'); urlInput.type = 'text'; urlInput.placeholder = '请先安装Hiframe插件,否则不能加载网页。输入网址后点击加载。'; urlInput.style.flexGrow = '1'; urlInput.style.padding = '5px'; urlInput.style.border = '1px solid #ddd'; urlInput.style.borderRadius = '4px'; urlContainer.appendChild(urlInput); // 预设翻译按钮点击事件 sogouBtn.addEventListener('click', () => { urlInput.value = 'fanyi.sogou.com'; loadBtn.click(); }); baiduBtn.addEventListener('click', () => { urlInput.value = 'fanyi.baidu.com'; loadBtn.click(); }); youdaoBtn.addEventListener('click', () => { urlInput.value = 'fanyi.youdao.com'; loadBtn.click(); }); // 加载按钮 const loadBtn = document.createElement('button'); loadBtn.textContent = '加载'; loadBtn.style.padding = '5px 10px'; loadBtn.style.border = 'none'; loadBtn.style.borderRadius = '4px'; loadBtn.style.backgroundColor = '#4285f4'; loadBtn.style.color = 'white'; loadBtn.style.cursor = 'pointer'; urlContainer.appendChild(loadBtn); // 创建iframe const iframe = document.createElement('iframe'); iframe.style.width = '100%'; iframe.style.height = 'calc(100% - 90px)'; iframe.style.border = 'none'; iframe.style.marginTop = '5px'; floatWindow.appendChild(iframe); // 设置移动端视图 const setMobileView = () => { const viewportMeta = document.createElement('meta'); viewportMeta.name = 'viewport'; viewportMeta.content = 'width=device-width, initial-scale=1.0'; iframe.contentDocument.head.appendChild(viewportMeta); }; // 拖动功能 let isDragging = false; let offsetX, offsetY; titleBar.addEventListener('mousedown', (e) => { isDragging = true; offsetX = e.clientX - floatWindow.getBoundingClientRect().left; offsetY = e.clientY - floatWindow.getBoundingClientRect().top; }); document.addEventListener('mousemove', (e) => { if (!isDragging) return; floatWindow.style.left = (e.clientX - offsetX) + 'px'; floatWindow.style.top = (e.clientY - offsetY) + 'px'; }); document.addEventListener('mouseup', () => { isDragging = false; }); // 按钮点击事件 floatBtn.addEventListener('click', () => { console.log('浮动按钮被点击'); floatWindow.style.display = floatWindow.style.display === 'none' ? 'block' : 'none'; }); // 最大化功能 maxBtn.addEventListener('click', () => { const windowWidth = window.innerWidth * 0.9; const windowHeight = window.innerHeight * 0.9; floatWindow.style.width = windowWidth + 'px'; floatWindow.style.height = windowHeight + 'px'; floatWindow.style.left = (window.innerWidth - windowWidth) / 2 + 'px'; floatWindow.style.top = (window.innerHeight - windowHeight) / 2 + 'px'; maxBtn.style.display = 'none'; // 隐藏最大化按钮 restoreBtn.style.display = 'block'; // 显示恢复按钮 }); // 恢复功能 restoreBtn.addEventListener('click', () => { floatWindow.style.width = '300px'; floatWindow.style.height = '400px'; restoreBtn.style.display = 'none'; // 隐藏恢复按钮 maxBtn.style.display = 'block'; // 显示最大化按钮 }); // 关闭功能 closeBtn.addEventListener('click', () => { floatWindow.style.display = 'none'; }); // 加载网页 loadBtn.addEventListener('click', () => { let url = urlInput.value.trim(); if (!url.startsWith('http://') && !url.startsWith('https://')) { url = 'https://' + url; } iframe.src = url; // 监听iframe加载完成事件 iframe.onload = function () { try { setMobileView(); } catch (e) { console.log('无法设置移动端视图:', e); } }; }); // 创建缩放控制按钮 const resizeHandle = document.createElement('div'); resizeHandle.style.position = 'absolute'; resizeHandle.style.right = '0'; resizeHandle.style.bottom = '0'; resizeHandle.style.width = '20px'; resizeHandle.style.height = '20px'; resizeHandle.style.cursor = 'nwse-resize'; resizeHandle.style.background = 'linear-gradient(135deg, transparent 0%, transparent 50%, #4285f4 50%, #4285f4 100%)'; floatWindow.appendChild(resizeHandle); // 缩放功能 let isResizing = false; resizeHandle.addEventListener('mousedown', (e) => { isResizing = true; e.stopPropagation(); }); document.addEventListener('mousemove', (e) => { if (!isResizing) return; const newWidth = e.clientX - floatWindow.getBoundingClientRect().left; const newHeight = e.clientY - floatWindow.getBoundingClientRect().top; floatWindow.style.width = Math.max(200, newWidth) + 'px'; floatWindow.style.height = Math.max(200, newHeight) + 'px'; document.addEventListener('mouseup', () => { if (isResizing) { isResizing = false; // 清除页面中的文本选择 if (window.getSelection) { window.getSelection().removeAllRanges(); } else if (document.selection) { document.selection.empty(); }} }); }); // 添加一些基础样式 GM_addStyle(` button { transition: all 0.2s; } button:hover { opacity: 0.8; } input:focus { outline: none; border-color: #4285f4 !important; } .resize-handle { position: absolute; right: 0; bottom: 0; width: 20px; height: 20px; cursor: nwse-resize; background: linear-gradient(135deg, transparent 0%, transparent 50%, #4285f4 50%, #4285f4 100%); } `); //加载页面后提示更新信息 //如果是iframe则不显示,如果标题不包含comfyui则不显示 if (window.self !== window.top|| document.title.indexOf('comfyui')==-1) { return; }else{ showToast(`25年5月更新:4.5 版本
1、可以编辑提示词了😄🎉🎉
2、新增🛜按钮,点击后可以在页面内打开翻译网站,需要安装Hiframe插件
3、新增🈳按钮,点击后把所有空格替换成_

如果您不想在所有网页启用此脚本,请把// @match *://*/* 替换成您想要显示的网站`,8000); } })();