您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
1.1.5:修复悬浮窗
当前为
// ==UserScript== // @name 123pan JSON秒传链接工具 // @namespace http://tampermonkey.net/ // @version 1.1.5 // @description 1.1.5:修复悬浮窗 // @author Tocpomk // @match *://*.www.123pan.com // @match *://www.123pan.cn // @match *://*.123865.com // @match *://*.123684.com // @match *://*.123912.com // @grant GM_addStyle // @grant GM_setValue // @grant GM_getValue // @run-at document-end // @license MIT // ==/UserScript== (function() { 'use strict'; // 添加样式 GM_addStyle(` #json-tool-float-btn { position: fixed; top: 50%; right: 20px; transform: translateY(-50%); width: 60px; height: 60px; background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); border: none; border-radius: 50%; color: white; font-size: 24px; cursor: pointer; box-shadow: 0 4px 15px rgba(0,0,0,0.2); z-index: 9999; transition: all 0.3s ease; display: flex; align-items: center; justify-content: center; user-select: none; animation: pulse 2s infinite; touch-action: none; } #json-tool-float-btn:hover { transform: translateY(-50%) scale(1.1); box-shadow: 0 6px 20px rgba(0,0,0,0.3); } #json-tool-float-btn:active { transform: translateY(-50%) scale(0.95); } #json-tool-float-btn.dragging { opacity: 0.8; cursor: grabbing; transform: none !important; box-shadow: 0 8px 25px rgba(0,0,0,0.4); } #json-tool-modal { position: fixed; top: 0; left: 0; width: 100%; height: 100%; background: rgba(0,0,0,0.5); z-index: 10000; display: flex; align-items: center; justify-content: center; opacity: 0; visibility: hidden; transition: all 0.4s cubic-bezier(0.32, 0.72, 0, 1); pointer-events: none; } #json-tool-modal.show { opacity: 1; visibility: visible; pointer-events: all; } #json-tool-content { width: 90%; height: 90%; max-width: 1200px; background: white; border-radius: 16px; box-shadow: 0 25px 50px -12px rgba(0,0,0,0.25); display: flex; flex-direction: column; overflow: hidden; transform: translateY(50px) scale(0.95); opacity: 0; transition: all 0.5s cubic-bezier(0.32, 0.72, 0, 1); } #json-tool-modal.show #json-tool-content { transform: translateY(0) scale(1); opacity: 1; } #json-tool-close { position: absolute; top: 18px; right: 18px; background: rgba(0,0,0,0.2); border: none; color: white; font-size: 26px; cursor: pointer; width: 42px; height: 42px; border-radius: 50%; transition: all 0.3s ease; z-index: 10001; display: flex; align-items: center; justify-content: center; } #json-tool-close:hover { background: rgba(0,0,0,0.5); transform: scale(1.15) rotate(90deg); } #json-tool-iframe { width: 100%; height: 100%; border: none; border-radius: 0 0 16px 16px; } #json-tool-header { height: 60px; background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); display: flex; align-items: center; justify-content: space-between; padding: 0 24px; color: white; font-weight: bold; font-size: 18px; position: relative; } #json-tool-title { display: flex; align-items: center; gap: 12px; } #json-tool-title svg { width: 24px; height: 24px; fill: white; } .json-tool-drag-handle { width: 100%; height: 30px; position: absolute; top: 0; left: 0; cursor: move; z-index: 1; } /* 响应式设计 */ @media (max-width: 768px) { #json-tool-content { width: 95%; height: 95%; } #json-tool-float-btn { width: 50px; height: 50px; font-size: 20px; right: 15px; } #json-tool-header { padding: 0 15px; height: 50px; font-size: 16px; } } @keyframes pulse { 0% { box-shadow: 0 0 0 0 rgba(102, 126, 234, 0.6); } 70% { box-shadow: 0 0 0 12px rgba(102, 126, 234, 0); } 100% { box-shadow: 0 0 0 0 rgba(102, 126, 234, 0); } } .json-tool-tooltip { position: absolute; top: -45px; left: 50%; transform: translateX(-50%); background: rgba(0,0,0,0.7); color: white; padding: 8px 12px; border-radius: 6px; font-size: 14px; white-space: nowrap; pointer-events: none; opacity: 0; transition: opacity 0.3s ease; } .json-tool-tooltip::after { content: ''; position: absolute; top: 100%; left: 50%; transform: translateX(-50%); border-width: 6px; border-style: solid; border-color: rgba(0,0,0,0.7) transparent transparent transparent; } #json-tool-float-btn:hover .json-tool-tooltip { opacity: 1; } #json-tool-header-btns { display: flex; align-items: center; gap: 8px; /* 减小间距 */ position: absolute; top: 50%; /* 垂直居中 */ right: 18px; transform: translateY(-50%); /* 确保精确垂直居中 */ z-index: 10001; } #json-tool-maximize, #json-tool-close { background: rgba(0,0,0,0.2); border: none; color: white; width: 36px; height: 36px; border-radius: 50%; display: flex; align-items: center; justify-content: center; transition: all 0.3s; padding: 0; margin: 0; } #json-tool-maximize:hover, #json-tool-close:hover { background: rgba(0,0,0,0.4); transform: scale(1.1); } #json-tool-maximize svg, #json-tool-close svg { width: 22px; height: 22px; display: block; margin: auto; } `); // 创建悬浮按钮 function createFloatButton() { const btn = document.createElement('button'); btn.id = 'json-tool-float-btn'; btn.innerHTML = ` <img src="https://ims.musejie.top/za/resource%20manager.svg" style="width:32px;height:32px;pointer-events:none;" /> <div class="json-tool-tooltip">拖拽移动 点击打开</div> `; btn.title = 'JSON秒传链接工具'; // 从存储中获取位置 const savedPosition = GM_getValue('floatButtonPosition', null); if (savedPosition) { btn.style.left = `${savedPosition.x}px`; btn.style.top = `${savedPosition.y}px`; btn.style.right = 'auto'; btn.style.transform = 'none'; } else { // 默认右侧20px 垂直居中 btn.style.right = '20px'; btn.style.top = '50%'; btn.style.left = 'auto'; btn.style.transform = 'translateY(-50%)'; } // 初始化时保证按钮可见 setTimeout(() => { ensureButtonInView(btn); }, 100); // 添加拖拽功能 let isDragging = false; let dragOffsetX, dragOffsetY; let justDragged = false; let dragStartX = 0, dragStartY = 0, dragMoved = false; btn.addEventListener('mousedown', startDrag); btn.addEventListener('touchstart', startDragTouch, { passive: false }); function startDrag(e) { e.preventDefault(); isDragging = true; dragMoved = false; btn.classList.add('dragging'); const rect = btn.getBoundingClientRect(); dragOffsetX = e.clientX - rect.left; dragOffsetY = e.clientY - rect.top; dragStartX = e.clientX; dragStartY = e.clientY; document.addEventListener('mousemove', onDrag); document.addEventListener('mouseup', stopDrag); } function startDragTouch(e) { if (e.touches.length !== 1) return; e.preventDefault(); isDragging = true; dragMoved = false; btn.classList.add('dragging'); const touch = e.touches[0]; const rect = btn.getBoundingClientRect(); dragOffsetX = touch.clientX - rect.left; dragOffsetY = touch.clientY - rect.top; document.addEventListener('touchmove', onDragTouch, { passive: false }); document.addEventListener('touchend', stopDragTouch); } function onDrag(e) { if (!isDragging) return; e.preventDefault(); const moveX = Math.abs(e.clientX - dragStartX); const moveY = Math.abs(e.clientY - dragStartY); if (moveX > 3 || moveY > 3) dragMoved = true; // 超过3像素才算拖拽 updatePosition(e.clientX, e.clientY); } function onDragTouch(e) { if (!isDragging || e.touches.length !== 1) return; e.preventDefault(); const touch = e.touches[0]; updatePosition(touch.clientX, touch.clientY); } function updatePosition(clientX, clientY) { const x = clientX - dragOffsetX; const y = clientY - dragOffsetY; // 限制按钮不超出屏幕边界 const maxX = window.innerWidth - btn.offsetWidth; const maxY = window.innerHeight - btn.offsetHeight; btn.style.left = `${Math.max(0, Math.min(x, maxX))}px`; btn.style.top = `${Math.max(0, Math.min(y, maxY))}px`; btn.style.right = 'auto'; btn.style.transform = 'none'; } // 保证按钮始终可见(右侧边界) function ensureButtonInView(btn) { const rect = btn.getBoundingClientRect(); const maxX = window.innerWidth - btn.offsetWidth; const maxY = window.innerHeight - btn.offsetHeight; let left = parseInt(btn.style.left || 0); let top = parseInt(btn.style.top || 0); let needReset = false; if (isNaN(left) || left < 0 || left > maxX) needReset = true; if (isNaN(top) || top < 0 || top > maxY) needReset = true; if (needReset) { // 重置到默认位置 btn.style.right = '20px'; btn.style.top = '50%'; btn.style.left = 'auto'; btn.style.transform = 'translateY(-50%)'; // 清除存储的错误位置 if (typeof GM_setValue === 'function') { GM_setValue('floatButtonPosition', null); } } } window.addEventListener('resize', () => ensureButtonInView(btn)); function stopDrag(e) { if (!isDragging) return; isDragging = false; btn.classList.remove('dragging'); // 保存位置 GM_setValue('floatButtonPosition', { x: parseInt(btn.style.left), y: parseInt(btn.style.top) }); document.removeEventListener('mousemove', onDrag); document.removeEventListener('mouseup', stopDrag); if (dragMoved) { justDragged = true; setTimeout(() => { justDragged = false; }, 200); } } function stopDragTouch(e) { if (!isDragging) return; isDragging = false; btn.classList.remove('dragging'); document.removeEventListener('touchmove', onDragTouch); document.removeEventListener('touchend', stopDragTouch); // 保存位置 GM_setValue('floatButtonPosition', { x: parseInt(btn.style.left), y: parseInt(btn.style.top) }); if (dragMoved) { justDragged = true; setTimeout(() => { justDragged = false; }, 200); } else { // 没有拖动,视为点击 showModal(); } } // 点击事件 btn.addEventListener('click', function(e) { if (justDragged) return; if (!isDragging && !dragMoved) { showModal(); } }); document.body.appendChild(btn); return btn; } // 创建弹窗 function createModal() { const modal = document.createElement('div'); modal.id = 'json-tool-modal'; modal.innerHTML = ` <div id="json-tool-content"> <div class="json-tool-drag-handle"></div> <div id="json-tool-header"> <div id="json-tool-title"> <svg viewBox="0 0 24 24"> <path d="M14,11H10V9h4V11z M14,8H10V6h4V8z M20,4V20H4V4H20 M20,2H4C2.9,2,2,2.9,2,4v16c0,1.1,0.9,2,2,2h16c1.1,0,2-0.9,2-2V4 C22,2.9,21.1,2,20,2L20,2z M16,15H8v-2h8V15z M16,18H8v-2h8V18z M6,15H4v2h2V15z M6,18H4v2h2V18z M6,6H4v8h2V6z"></path> </svg> <span>JSON秒传链接工具</span> </div> <div id="json-tool-header-btns"> <button id="json-tool-maximize" title="最大化"> <svg viewBox="0 0 24 24"> <path id="json-tool-maximize-icon" d="M3 3h7v2H5v5H3V3zm11 0h7v7h-2V5h-5V3zm7 11v7h-7v-2h5v-5h2zm-11 7H3v-7h2v5h5v2z"/> </svg> </button> <button id="json-tool-close" title="关闭"> <svg viewBox="0 0 24 24"> <path d="M18.3 5.71a1 1 0 0 0-1.41 0L12 10.59 7.11 5.7A1 1 0 0 0 5.7 7.11L10.59 12l-4.89 4.89a1 1 0 1 0 1.41 1.41L12 13.41l4.89 4.89a1 1 0 0 0 1.41-1.41L13.41 12l4.89-4.89a1 1 0 0 0 0-1.4z"/> </svg> </button> </div> </div> <iframe id="json-tool-iframe" src="https://123.487510.xyz/"></iframe> </div> `; // 关闭按钮事件 modal.querySelector('#json-tool-close').addEventListener('click', hideModal); // 点击背景关闭 modal.addEventListener('click', function(e) { if (e.target === modal) { hideModal(); } }); // ESC键关闭 document.addEventListener('keydown', function(e) { if (e.key === 'Escape') { hideModal(); } }); // 添加弹窗拖拽功能 let isModalDragging = false; let modalStartX, modalStartY; const dragHandle = modal.querySelector('.json-tool-drag-handle'); const content = modal.querySelector('#json-tool-content'); dragHandle.addEventListener('mousedown', startModalDrag); function startModalDrag(e) { isModalDragging = true; modalStartX = e.clientX; modalStartY = e.clientY; content.style.transition = 'none'; // 拖动时禁用过渡效果 document.addEventListener('mousemove', onModalDrag); document.addEventListener('mouseup', stopModalDrag); } function onModalDrag(e) { if (!isModalDragging) return; const deltaX = e.clientX - modalStartX; const deltaY = e.clientY - modalStartY; content.style.transform = `translate(${deltaX}px, ${deltaY}px)`; } function stopModalDrag() { if (!isModalDragging) return; isModalDragging = false; content.style.transition = ''; content.style.transform = ''; document.removeEventListener('mousemove', onModalDrag); document.removeEventListener('mouseup', stopModalDrag); } // 最大化/还原功能 const maximizeBtn = modal.querySelector('#json-tool-maximize'); const maximizeIcon = modal.querySelector('#json-tool-maximize-icon'); const contentBox = modal.querySelector('#json-tool-content'); let isMaximized = false; maximizeBtn.addEventListener('click', function() { isMaximized = !isMaximized; if (isMaximized) { contentBox.style.width = '100vw'; contentBox.style.height = '100vh'; contentBox.style.maxWidth = '100vw'; contentBox.style.maxHeight = '100vh'; contentBox.style.borderRadius = '0'; contentBox.style.top = '0'; contentBox.style.left = '0'; contentBox.style.position = 'fixed'; contentBox.style.zIndex = '10002'; maximizeIcon.innerHTML = '<path d="M7 14H5v5h5v-2H7v-3zm7 3v2h5v-5h-2v3h-3zm3-10V5h-3V3h5v5h-2V7zm-7-2V3H3v5h2V5h3z"/>'; } else { contentBox.style.width = ''; contentBox.style.height = ''; contentBox.style.maxWidth = '1200px'; contentBox.style.maxHeight = ''; contentBox.style.borderRadius = '16px'; contentBox.style.top = ''; contentBox.style.left = ''; contentBox.style.position = ''; contentBox.style.zIndex = ''; maximizeIcon.innerHTML = '<path d="M3 3h7v2H5v5H3V3zm11 0h7v7h-2V5h-5V3zm7 11v7h-7v-2h5v-5h2zm-11 7H3v-7h2v5h5v2z"/>'; } }); document.body.appendChild(modal); return modal; } // 显示弹窗 function showModal() { const modal = document.getElementById('json-tool-modal'); if (modal) { document.body.style.overflow = 'hidden'; setTimeout(() => { modal.classList.add('show'); }, 10); } } // 隐藏弹窗 function hideModal() { const modal = document.getElementById('json-tool-modal'); if (modal) { modal.classList.remove('show'); setTimeout(() => { document.body.style.overflow = ''; }, 300); // 匹配动画时间 } } // 初始化 function init() { // 等待页面加载完成 if (document.readyState === 'loading') { document.addEventListener('DOMContentLoaded', function() { createFloatButton(); createModal(); }); } else { createFloatButton(); createModal(); } } // 启动脚本 init(); // 只在油猴环境下监听 iframe 消息,实现剪贴板代理 window.addEventListener('message', async function(event) { // 只允许信任的 iframe 域名 if (!event.origin.startsWith('https://123.487510.xyz')) return; const { type, text } = event.data || {}; if (type === 'copyToClipboard') { try { await navigator.clipboard.writeText(text); event.source.postMessage({ type: 'copyResult', success: true }, event.origin); } catch (e) { event.source.postMessage({ type: 'copyResult', success: false, error: e.message }, event.origin); } } if (type === 'pasteFromClipboard') { try { const clipText = await navigator.clipboard.readText(); event.source.postMessage({ type: 'pasteResult', success: true, text: clipText }, event.origin); } catch (e) { event.source.postMessage({ type: 'pasteResult', success: false, error: e.message }, event.origin); } } }); // 检查并重置按钮位置,超出边界则重置到默认 function ensureButtonInView(btn) { const rect = btn.getBoundingClientRect(); const maxX = window.innerWidth - btn.offsetWidth; const maxY = window.innerHeight - btn.offsetHeight; let left = parseInt(btn.style.left || 0); let top = parseInt(btn.style.top || 0); let needReset = false; if (isNaN(left) || left < 0 || left > maxX) needReset = true; if (isNaN(top) || top < 0 || top > maxY) needReset = true; if (needReset) { // 重置到默认位置 btn.style.right = '20px'; btn.style.top = '50%'; btn.style.left = 'auto'; btn.style.transform = 'translateY(-50%)'; // 清除存储的错误位置 if (typeof GM_setValue === 'function') { GM_setValue('floatButtonPosition', null); } } } // 监测“全部文件”菜单是否存在,动态显示/隐藏悬浮按钮 function monitorMenuAndToggleButton() { // 获取悬浮按钮 const floatBtn = document.getElementById('json-tool-float-btn'); if (!floatBtn) return; function checkAndToggle() { // 检查是否存在“全部文件”菜单 const menu = document.querySelector('.with-side-menu-layout-sider-menu--item.sider-menu-item.active .with-side-menu-layout-sider-menu--item-label.sider-menu-item-label'); if (menu && menu.textContent.trim() === '全部文件') { ensureButtonInView(floatBtn); // 检查并重置位置 floatBtn.style.display = ''; } else { floatBtn.style.display = 'none'; } } // 初始检查 checkAndToggle(); // 监听 DOM 变化 const observer = new MutationObserver(checkAndToggle); observer.observe(document.body, { childList: true, subtree: true }); // 页面切换时也检查 window.addEventListener('hashchange', checkAndToggle); window.addEventListener('popstate', checkAndToggle); } // 在初始化后调用,确保按钮已创建 setTimeout(monitorMenuAndToggleButton, 1000); })();