// ==UserScript== // @name 网页元素调整工具 (Element Adjuster) // @namespace http://tampermonkey.net/ // @version 3.4 // @description 调整网页元素的宽度、高度或移除元素,支持中英文切换 // @author ZZW // @match *://*/* // @grant GM_setValue // @grant GM_getValue // @grant GM_registerMenuCommand // @run-at document-end // ==/UserScript== (function() { 'use strict'; // 语言包 - 增加了规则显示相关翻译 const i18n = { zh: { title: "网页元素调整工具", general: "通用", elementAdjust: "元素调整", rulesDisplay: "规则显示", ruleList: "调整规则列表", noRules: "暂无调整规则", element: "元素", modification: "修改内容", restore: "恢复", selectElement: "选择元素", selectElementHint: "点击页面上的元素进行选择...", parentElement: "父元素", childElement: "子元素", width: "宽度 (px)", height: "高度 (px)", remove: "移除元素", resetSite: "重置本网站", minimize: "最小化", close: "关闭", selected: "已选择:", noElement: "未选择元素", apply: "应用", resetConfirm: "确定要重置本网站的所有元素调整吗?", language: "语言", save: "保存" }, en: { title: "Element Adjuster", general: "General", elementAdjust: "Element Adjust", rulesDisplay: "Rules Display", ruleList: "Adjustment Rules List", noRules: "No adjustment rules", element: "Element", modification: "Modification", restore: "Restore", selectElement: "Select Element", selectElementHint: "Click an element on the page to select...", parentElement: "Parent Element", childElement: "Child Element", width: "Width (px)", height: "Height (px)", remove: "Remove Element", resetSite: "Reset This Site", minimize: "Minimize", close: "Close", selected: "Selected:", noElement: "No element selected", apply: "Apply", resetConfirm: "Are you sure to reset all element adjustments for this site?", language: "Language", save: "Save" } }; // 全局状态 let currentLang = GM_getValue('elementAdjuster_lang', 'zh'); let isSelecting = false; let selectedElement = null; let originalStyles = new Map(); let siteKey = window.location.hostname; let panelMinimized = false; let panelRefs = {}; let isDragging = false; let dragOffset = { x: 0, y: 0 }; const NORMAL_WIDTH = '700px'; const NORMAL_HEIGHT = '500px'; const MINIMIZED_WIDTH = '80px'; const MINIMIZED_HEIGHT = '66px'; // 初始化 function init() { addStyles(); createPanel(); restoreOriginalStyles(); updateRulesDisplay(); observePanelMenu(); } // 显示面板函数 function showPanel() { const panel = panelRefs.panel; if (panel) { panel.style.display = 'flex'; // 确保面板在可视区域内 const viewportWidth = window.innerWidth; const viewportHeight = window.innerHeight; const panelWidth = panel.offsetWidth; const panelHeight = panel.offsetHeight; let left = parseInt(panel.style.left) || 100; let top = parseInt(panel.style.top) || 100; // 如果面板超出视口,调整位置 if (left + panelWidth > viewportWidth) { left = Math.max(0, viewportWidth - panelWidth - 20); } if (top + panelHeight > viewportHeight) { top = Math.max(0, viewportHeight - panelHeight - 20); } panel.style.left = left + 'px'; panel.style.top = top + 'px'; } } // 观察PanelMenu并绑定设置按钮事件 function observePanelMenu() { // 尝试直接查找并绑定 const bindSettingButton = () => { // 查找包含"⚙ 设置"文本的菜单元素 const settingBtn = Array.from(document.querySelectorAll('*')).find(el => el.textContent.trim() === '⚙ 设置' ); if (settingBtn) { settingBtn.addEventListener('click', (e) => { e.stopPropagation(); showPanel(); // 调用显示面板函数 }); return true; } return false; }; // 立即尝试绑定 if (bindSettingButton()) return; // 如果未找到,则使用MutationObserver监听面板菜单加载 // eslint-disable-next-line no-unused-vars const observer = new MutationObserver((_mutations) => { if (bindSettingButton()) { observer.disconnect(); } }); // 监听整个文档的变化 observer.observe(document.body, { childList: true, subtree: true, characterData: true }); // 5秒后自动停止监听,避免内存泄漏 setTimeout(() => observer.disconnect(), 5000); } // 添加Tampermonkey菜单命令 GM_registerMenuCommand( currentLang === 'zh' ? '打开元素调整工具' : 'Open Element Adjuster', showPanel ); // 样式 function addStyles() { const style = document.createElement('style'); style.textContent = ` .element-highlight { outline: 3px solid #e74c3c !important; outline-offset: 2px; transition: all 0.2s ease; } .selection-mode { cursor: crosshair !important; } .setting-panel { position: fixed; top: 100px; left: 100px; width: ${NORMAL_WIDTH}; height: ${NORMAL_HEIGHT}; background: white; border: 1px solid #ccc; border-radius: 8px; box-shadow: 0 4px 20px rgba(0,0,0,0.15); box-sizing: border-box; z-index: 999999; display: none; flex-direction: column; transition: width 0.2s, height 0.2s; transform-origin: right top; } .panel-header { display: flex; justify-content: space-between; align-items: center; padding: 15px 20px; border-bottom: 1px solid #eee; cursor: move; user-select: none; } .panel-body { display: flex; flex: 1; overflow: hidden; } .menu-sidebar { width: 180px; border-right: 1px solid #eee; overflow-y: auto; } .menu-item { padding: 12px 20px; cursor: pointer; transition: background 0.2s; border-left: 3px solid transparent; } .menu-item.active { background: #f0f7ff; border-left-color: #1890ff; color: #1890ff; font-weight: 500; } .content-area { flex: 1; padding: 20px; overflow-y: auto; display: none; } .content-area.active { display: block; } .setting-group { margin-bottom: 25px; } .setting-label { display: block; margin-bottom: 8px; font-weight: 500; color: #333; } .lang-select, .form-control { width: 100%; padding: 8px 12px; border: 1px solid #ddd; border-radius: 4px; box-sizing: border-box; } .btn { padding: 8px 16px; border: none; border-radius: 4px; cursor: pointer; font-size: 14px; transition: all 0.2s; } .btn-primary { background: #1890ff; color: white; } .btn-light { background: white; color: #333; border: 1px solid #ddd; } .btn-danger { background: #ff7875; color: white; } .btn-warning { background: #faad14; color: white; } .input-group { display: flex; gap: 10px; align-items: center; margin-bottom: 15px; } .input-group input { flex: 1; } .select-btn-group { display: flex; gap: 0; margin-bottom: 15px; box-shadow: 0 1px 2px rgba(0,0,0,0.1); } .select-btn-group .btn { border-radius: 0; flex: none; } .control-btn-group { display: flex; gap: 5px; } .control-btn { width: 36px; height: 36px; display: flex; align-items: center; justify-content: center; padding: 0; font-size: 16px; } .save-btn { margin-top: 10px; } /* 新增:规则显示相关样式 */ .rules-list { margin-top: 15px; } .rule-item { padding: 12px; border: 1px solid #eee; border-radius: 4px; margin-bottom: 10px; background: #f9f9f9; } .rule-element { font-family: monospace; font-size: 13px; margin-bottom: 8px; color: #666; word-break: break-all; } .rule-modifications { font-size: 14px; margin-bottom: 8px; } .rule-mod-item { display: flex; align-items: center; gap: 5px; margin-bottom: 4px; } .rule-actions { display: flex; justify-content: flex-end; gap: 8px; } `; document.head.appendChild(style); } // 面板创建 function createPanel() { const panel = document.createElement('div'); panel.className = 'setting-panel'; document.body.appendChild(panel); // 标题栏 const header = document.createElement('div'); header.className = 'panel-header'; header.addEventListener('mousedown', startDrag); header.style.display = 'flex'; header.style.justifyContent = 'space-between'; header.style.alignItems = 'center'; // 最小化按钮(左) const minBtn = createButton('—', 'btn-light', i18n[currentLang].minimize, toggleMinimize); minBtn.className += ' control-btn'; minBtn.addEventListener('mousedown', e => e.stopPropagation()); // 标题(中) const title = document.createElement('h3'); title.textContent = i18n[currentLang].title; title.style.margin = '0'; title.style.fontSize = '16px'; title.style.flex = '1'; title.style.textAlign = 'center'; // 关闭按钮(右) const closeBtn = createButton('✕', 'btn-danger', i18n[currentLang].close, () => { panel.style.display = 'none'; }); closeBtn.className += ' control-btn'; closeBtn.addEventListener('mousedown', e => e.stopPropagation()); // 组装标题栏 header.appendChild(minBtn); header.appendChild(title); header.appendChild(closeBtn); panel.appendChild(header); // 主体 const body = document.createElement('div'); body.className = 'panel-body'; // 侧边栏 const sidebar = document.createElement('div'); sidebar.className = 'menu-sidebar'; const menus = [ {id: 'general', text: i18n[currentLang].general}, {id: 'element', text: i18n[currentLang].elementAdjust}, {id: 'rules', text: i18n[currentLang].rulesDisplay} // 新增 ]; menus.forEach(menu => { const item = createMenuItem(menu.id, menu.text); sidebar.appendChild(item); }); // 内容区 - 增加规则显示内容 const contentWrap = document.createElement('div'); contentWrap.style.flex = '1'; contentWrap.style.overflow = 'hidden'; contentWrap.appendChild(createGeneralContent()); contentWrap.appendChild(createElementContent()); contentWrap.appendChild(createRulesContent()); // 新增 body.appendChild(sidebar); body.appendChild(contentWrap); panel.appendChild(body); // 存储引用 - 增加规则显示相关引用 panelRefs = { panel, minBtn, closeBtn, title, menuItems: sidebar.querySelectorAll('.menu-item'), contentAreas: contentWrap.querySelectorAll('.content-area'), langSelect: contentWrap.querySelector('#lang-select'), saveBtn: contentWrap.querySelector('#save-settings'), selectBtn: contentWrap.querySelector('#select-element'), parentBtn: contentWrap.querySelector('#parent-element'), childBtn: contentWrap.querySelector('#child-element'), currentElementDiv: contentWrap.querySelector('#current-element'), widthInput: contentWrap.querySelector('#width-input'), heightInput: contentWrap.querySelector('#height-input'), widthApply: contentWrap.querySelector('#width-apply'), heightApply: contentWrap.querySelector('#height-apply'), removeBtn: contentWrap.querySelector('#remove-element'), resetBtn: contentWrap.querySelector('#reset-site'), rulesList: contentWrap.querySelector('#rules-list') // 新增 }; } // 创建规则显示内容区域 function createRulesContent() { const content = document.createElement('div'); content.className = 'content-area'; content.dataset.content = 'rules'; const title = document.createElement('h3'); title.textContent = i18n[currentLang].ruleList; title.style.marginTop = '0'; const rulesList = document.createElement('div'); rulesList.id = 'rules-list'; rulesList.className = 'rules-list'; rulesList.textContent = i18n[currentLang].noRules; content.append(title, rulesList); return content; } function createButton(text, className, title, clickHandler) { const btn = document.createElement('button'); btn.textContent = text; btn.className = `btn ${className}`; btn.title = title; btn.addEventListener('click', clickHandler); return btn; } function createMenuItem(id, text) { const item = document.createElement('div'); item.className = `menu-item ${id === 'general' ? 'active' : ''}`; item.textContent = text; item.dataset.menu = id; item.addEventListener('click', () => switchMenu(id)); return item; } function createGeneralContent() { const content = document.createElement('div'); content.className = 'content-area active'; content.dataset.content = 'general'; const langGroup = document.createElement('div'); langGroup.className = 'setting-group'; const langLabel = document.createElement('label'); langLabel.className = 'setting-label'; langLabel.textContent = i18n[currentLang].language; const langSelect = document.createElement('select'); langSelect.id = 'lang-select'; langSelect.className = 'lang-select'; langSelect.innerHTML = ``; langSelect.value = currentLang; langSelect.style.appearance = 'none'; langSelect.style.webkitAppearance = 'none'; langSelect.style.mozAppearance = 'none'; const saveBtn = createButton(i18n[currentLang].save, 'btn-primary', '', saveGeneralSettings); saveBtn.id = 'save-settings'; saveBtn.className += ' save-btn'; langGroup.append(langLabel, langSelect, saveBtn); content.appendChild(langGroup); return content; } function createElementContent() { const content = document.createElement('div'); content.className = 'content-area'; content.dataset.content = 'element'; // 选择按钮组 const selectBtnGroup = document.createElement('div'); selectBtnGroup.className = 'select-btn-group'; const selectBtn = createButton(i18n[currentLang].selectElement, 'btn-primary', '', startSelecting); selectBtn.id = 'select-element'; const parentBtn = createButton('↑', 'btn-light', i18n[currentLang].parentElement, () => switchElement('parent')); parentBtn.id = 'parent-element'; parentBtn.disabled = true; const childBtn = createButton('↓', 'btn-light', i18n[currentLang].childElement, () => switchElement('child')); childBtn.id = 'child-element'; childBtn.disabled = true; selectBtnGroup.append(selectBtn, parentBtn, childBtn); // 元素显示 const elementDisplay = document.createElement('div'); elementDisplay.style.marginBottom = '15px'; const elementLabel = document.createElement('div'); elementLabel.style.fontWeight = '500'; elementLabel.style.marginBottom = '5px'; elementLabel.textContent = i18n[currentLang].selected; const currentElementDiv = document.createElement('div'); currentElementDiv.id = 'current-element'; currentElementDiv.style.padding = '10px'; currentElementDiv.style.border = '1px solid #eee'; currentElementDiv.style.borderRadius = '4px'; currentElementDiv.textContent = i18n[currentLang].noElement; elementDisplay.append(elementLabel, currentElementDiv); // 宽度调整 const widthGroup = document.createElement('div'); widthGroup.className = 'input-group'; const widthInput = createInput('number', i18n[currentLang].width, 'width-input'); const widthApply = createButton(i18n[currentLang].apply, 'btn-primary', '', () => applyDimension('width')); widthApply.id = 'width-apply'; widthApply.disabled = true; widthGroup.append(widthInput, widthApply); // 高度调整 const heightGroup = document.createElement('div'); heightGroup.className = 'input-group'; const heightInput = createInput('number', i18n[currentLang].height, 'height-input'); const heightApply = createButton(i18n[currentLang].apply, 'btn-primary', '', () => applyDimension('height')); heightApply.id = 'height-apply'; heightApply.disabled = true; heightGroup.append(heightInput, heightApply); // 操作按钮 const actionBtns = document.createElement('div'); actionBtns.style.display = 'flex'; actionBtns.style.gap = '10px'; const removeBtn = createButton(i18n[currentLang].remove, 'btn-danger', '', removeSelectedElement); removeBtn.id = 'remove-element'; removeBtn.disabled = true; const resetBtn = createButton(i18n[currentLang].resetSite, 'btn-warning', '', resetSiteStyles); resetBtn.id = 'reset-site'; actionBtns.append(removeBtn, resetBtn); content.append(selectBtnGroup, elementDisplay, widthGroup, heightGroup, actionBtns); return content; } function createInput(type, placeholder, id) { const input = document.createElement('input'); input.type = type; input.id = id; input.min = 0; input.className = 'form-control'; input.placeholder = placeholder; input.disabled = true; return input; } // 核心功能 function toggleMinimize() { panelMinimized = !panelMinimized; const panel = panelRefs.panel; const body = panel.querySelector('.panel-body'); const { minBtn, title, closeBtn } = panelRefs; if (panelMinimized) { panel.style.width = MINIMIZED_WIDTH; panel.style.height = MINIMIZED_HEIGHT; body.style.display = 'none'; title.style.display = 'none'; closeBtn.style.display = 'none'; // 最小化时隐藏关闭按钮 minBtn.textContent = '▷'; minBtn.style.width = 'auto'; minBtn.style.padding = '0 10px'; } else { panel.style.width = NORMAL_WIDTH; panel.style.height = NORMAL_HEIGHT; body.style.display = 'flex'; title.style.display = 'block'; closeBtn.style.display = 'flex'; // 恢复时显示关闭按钮 minBtn.textContent = '—'; minBtn.style.width = '36px'; minBtn.style.padding = '0'; } } function startDrag(e) { if (panelMinimized) return; isDragging = true; const panel = panelRefs.panel; const rect = panel.getBoundingClientRect(); dragOffset.x = e.clientX - rect.left; dragOffset.y = e.clientY - rect.top; panel.style.transition = 'none'; document.body.style.userSelect = 'none'; const handleDrag = (e) => { if (!isDragging) return; const x = e.clientX - dragOffset.x; const y = e.clientY - dragOffset.y; const viewportWidth = window.innerWidth; const viewportHeight = window.innerHeight; const panelWidth = panel.offsetWidth; const panelHeight = panel.offsetHeight; const limitedX = Math.max(0, Math.min(x, viewportWidth - panelWidth / 4)); const limitedY = Math.max(0, Math.min(y, viewportHeight - panelHeight / 4)); panel.style.left = `${limitedX}px`; panel.style.top = `${limitedY}px`; panel.style.transform = 'none'; }; const endDrag = () => { isDragging = false; panel.style.transition = ''; document.body.style.userSelect = ''; document.removeEventListener('mousemove', handleDrag); document.removeEventListener('mouseup', endDrag); }; document.addEventListener('mousemove', handleDrag); document.addEventListener('mouseup', endDrag); } function switchMenu(menuId) { panelRefs.menuItems.forEach(item => { item.classList.toggle('active', item.dataset.menu === menuId); }); panelRefs.contentAreas.forEach(area => { area.classList.toggle('active', area.dataset.content === menuId); }); // 如果切换到规则显示菜单,更新规则列表 if (menuId === 'rules') { updateRulesDisplay(); } } function saveGeneralSettings() { const newLang = panelRefs.langSelect.value; if (newLang !== currentLang) { currentLang = newLang; GM_setValue('elementAdjuster_lang', currentLang); updateLanguageText(); alert(currentLang === 'zh' ? '设置已保存' : 'Settings saved'); } } // 更新语言文本 - 增加规则显示相关文本更新 function updateLanguageText() { panelRefs.title.textContent = i18n[currentLang].title; panelRefs.minBtn.title = i18n[currentLang].minimize; panelRefs.closeBtn.title = i18n[currentLang].close; panelRefs.saveBtn.textContent = i18n[currentLang].save; const menuItems = panelRefs.menuItems; menuItems[0].textContent = i18n[currentLang].general; menuItems[1].textContent = i18n[currentLang].elementAdjust; menuItems[2].textContent = i18n[currentLang].rulesDisplay; // 新增 panelRefs.selectBtn.textContent = i18n[currentLang].selectElement; panelRefs.parentBtn.title = i18n[currentLang].parentElement; panelRefs.childBtn.title = i18n[currentLang].childElement; panelRefs.currentElementDiv.textContent = selectedElement ? getElementDescription(selectedElement) : i18n[currentLang].noElement; panelRefs.widthInput.placeholder = i18n[currentLang].width; panelRefs.heightInput.placeholder = i18n[currentLang].height; panelRefs.widthApply.textContent = i18n[currentLang].apply; panelRefs.heightApply.textContent = i18n[currentLang].apply; panelRefs.removeBtn.textContent = i18n[currentLang].remove; panelRefs.resetBtn.textContent = i18n[currentLang].resetSite; if (panelRefs.rulesList) { const rulesContent = panelRefs.rulesList.closest('.content-area'); if (rulesContent) { rulesContent.querySelector('h3').textContent = i18n[currentLang].ruleList; } updateRulesDisplay(); } } function startSelecting() { if (isSelecting) return; isSelecting = true; const { selectBtn, currentElementDiv } = panelRefs; document.body.classList.add('selection-mode'); currentElementDiv.textContent = i18n[currentLang].selectElementHint; selectBtn.disabled = true; const selectHandler = (e) => { e.preventDefault(); e.stopPropagation(); selectedElement = e.target; document.querySelectorAll('.element-highlight').forEach(el => { el.classList.remove('element-highlight'); }); selectedElement.classList.add('element-highlight'); currentElementDiv.textContent = getElementDescription(selectedElement); updateElementControls(); document.body.classList.remove('selection-mode'); document.removeEventListener('click', selectHandler, true); selectBtn.disabled = false; isSelecting = false; }; document.addEventListener('click', selectHandler, true); const escHandler = (e) => { if (e.key === 'Escape' && isSelecting) { document.body.classList.remove('selection-mode'); document.removeEventListener('click', selectHandler, true); document.removeEventListener('keydown', escHandler); currentElementDiv.textContent = selectedElement ? getElementDescription(selectedElement) : i18n[currentLang].noElement; selectBtn.disabled = false; isSelecting = false; } }; document.addEventListener('keydown', escHandler); } function switchElement(type) { if (!selectedElement) return; let newElement = null; if (type === 'parent') { newElement = selectedElement.parentElement; } else if (type === 'child') { newElement = selectedElement.firstElementChild; } if (newElement && newElement !== selectedElement) { selectedElement.classList.remove('element-highlight'); selectedElement = newElement; selectedElement.classList.add('element-highlight'); panelRefs.currentElementDiv.textContent = getElementDescription(selectedElement); updateElementControls(); } } function updateElementControls() { panelRefs.parentBtn.disabled = !selectedElement.parentElement; panelRefs.childBtn.disabled = !selectedElement.firstElementChild; panelRefs.widthInput.disabled = false; panelRefs.heightInput.disabled = false; panelRefs.widthApply.disabled = false; panelRefs.heightApply.disabled = false; panelRefs.removeBtn.disabled = false; loadElementStyles(); } function loadElementStyles() { if (!selectedElement) return; const computedStyle = window.getComputedStyle(selectedElement); panelRefs.widthInput.value = Math.round(parseFloat(computedStyle.width)); panelRefs.heightInput.value = Math.round(parseFloat(computedStyle.height)); } function applyDimension(type) { if (!selectedElement) return; const input = type === 'width' ? panelRefs.widthInput : panelRefs.heightInput; const value = input.value.trim(); if (!value || isNaN(value) || parseInt(value) < 0) { alert(currentLang === 'zh' ? '请输入有效的数值' : 'Please enter a valid number'); return; } saveOriginalStyle(selectedElement); selectedElement.style[type] = `${value}px`; selectedElement.style.boxSizing = 'border-box'; saveSiteStyles(); updateRulesDisplay(); } function removeSelectedElement() { if (!selectedElement) return; if (confirm(currentLang === 'zh' ? '确定要移除这个元素吗?' : 'Are you sure to remove this element?')) { saveOriginalStyle(selectedElement); selectedElement.style.display = 'none'; selectedElement.classList.remove('element-highlight'); saveSiteStyles(); updateRulesDisplay(); selectedElement = null; resetElementInfo(); } } function resetElementInfo() { panelRefs.currentElementDiv.textContent = i18n[currentLang].noElement; panelRefs.parentBtn.disabled = true; panelRefs.childBtn.disabled = true; panelRefs.widthInput.disabled = true; panelRefs.heightInput.disabled = true; panelRefs.widthApply.disabled = true; panelRefs.heightApply.disabled = true; panelRefs.removeBtn.disabled = true; } // 更新规则显示列表 function updateRulesDisplay() { const rulesList = panelRefs.rulesList; if (!rulesList) return; rulesList.innerHTML = ''; if (originalStyles.size === 0) { rulesList.textContent = i18n[currentLang].noRules; return; } originalStyles.forEach((origStyle, elementKey) => { const element = document.querySelector(elementKey); if (!element) return; const currentStyle = { width: element.style.width, height: element.style.height, display: element.style.display }; const ruleItem = document.createElement('div'); ruleItem.className = 'rule-item'; const elementSelector = document.createElement('div'); elementSelector.className = 'rule-element'; elementSelector.textContent = elementKey; ruleItem.appendChild(elementSelector); const modifications = document.createElement('div'); modifications.className = 'rule-modifications'; if (currentStyle.width && currentStyle.width !== origStyle.width) { const modItem = document.createElement('div'); modItem.className = 'rule-mod-item'; modItem.innerHTML = `${i18n[currentLang].width}: ${origStyle.width || i18n[currentLang].original} → ${currentStyle.width}`; modifications.appendChild(modItem); } if (currentStyle.height && currentStyle.height !== origStyle.height) { const modItem = document.createElement('div'); modItem.className = 'rule-mod-item'; modItem.innerHTML = `${i18n[currentLang].height}: ${origStyle.height || i18n[currentLang].original} → ${currentStyle.height}`; modifications.appendChild(modItem); } // 显示状态修改(是否被移除) if (currentStyle.display === 'none' && currentStyle.display !== origStyle.display) { const modItem = document.createElement('div'); modItem.className = 'rule-mod-item'; modItem.innerHTML = `${i18n[currentLang].remove}: ${i18n[currentLang].yes}`; modifications.appendChild(modItem); } ruleItem.appendChild(modifications); const actions = document.createElement('div'); actions.className = 'rule-actions'; const restoreBtn = createButton(i18n[currentLang].restore, 'btn-light', '', () => { element.style.width = origStyle.width; element.style.height = origStyle.height; element.style.display = origStyle.display; element.style.boxSizing = origStyle.boxSizing; originalStyles.delete(elementKey); saveSiteStyles(); updateRulesDisplay(); if (selectedElement === element) { selectedElement = null; resetElementInfo(); } }); actions.appendChild(restoreBtn); ruleItem.appendChild(actions); rulesList.appendChild(ruleItem); }); } // 工具函数 function getElementDescription(element) { return `${element.tagName.toLowerCase()}${element.id ? '#' + element.id : ''}${element.className ? '.' + element.className.split(' ').join('.') : ''}`; } function saveOriginalStyle(element) { const elementKey = getElementKey(element); if (!originalStyles.has(elementKey)) { originalStyles.set(elementKey, { width: element.style.width, height: element.style.height, display: element.style.display, boxSizing: element.style.boxSizing }); } } function getElementKey(element) { let path = []; let current = element; while (current && current.nodeType === Node.ELEMENT_NODE) { let selector = current.tagName.toLowerCase(); if (current.id) { selector += `#${current.id}`; path.unshift(selector); break; } if (current.className) { selector += `.${current.className.split(' ').filter(c => c).join('.')}`; } let index = 0; let sibling = current.previousSibling; while (sibling) { if (sibling.nodeType === Node.ELEMENT_NODE && sibling.tagName === current.tagName) { index++; } sibling = sibling.previousSibling; } if (index > 0) { selector += `:nth-of-type(${index + 1})`; } path.unshift(selector); current = current.parentElement; } return path.join(' > '); } function saveSiteStyles() { const styles = {}; originalStyles.forEach((origStyle, elementKey) => { const element = document.querySelector(elementKey); if (element) { styles[elementKey] = { width: element.style.width, height: element.style.height, display: element.style.display, boxSizing: element.style.boxSizing }; } }); GM_setValue(`elementAdjuster_${siteKey}`, JSON.stringify(styles)); } function restoreOriginalStyles() { const savedStyles = GM_getValue(`elementAdjuster_${siteKey}`, '{}'); try { const styles = JSON.parse(savedStyles); Object.entries(styles).forEach(([elementKey, style]) => { const element = document.querySelector(elementKey); if (element) { saveOriginalStyle(element); element.style.width = style.width; element.style.height = style.height; element.style.display = style.display; element.style.boxSizing = style.boxSizing; } }); } catch (e) { console.error('Failed to restore styles:', e); } } function resetSiteStyles() { if (!confirm(i18n[currentLang].resetConfirm)) return; originalStyles.forEach((origStyle, elementKey) => { const element = document.querySelector(elementKey); if (element) { element.style.width = origStyle.width; element.style.height = origStyle.height; element.style.display = origStyle.display; element.style.boxSizing = origStyle.boxSizing; element.classList.remove('element-highlight'); } }); GM_setValue(`elementAdjuster_${siteKey}`, '{}'); originalStyles.clear(); selectedElement = null; resetElementInfo(); updateRulesDisplay(); } // 启动 init(); })();