// ==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();
})();