`;
}
function openSettings() {
const existing = document.querySelector('.mt-settings-overlay');
if (existing) existing.remove();
const overlay = document.createElement('div');
overlay.className = 'mt-settings-overlay';
overlay.innerHTML = buildSettingsHTML();
document.body.appendChild(overlay);
overlay.querySelector('#mt-close-btn').addEventListener('click', () => overlay.remove());
overlay.querySelector('#mt-save-btn').addEventListener('click', () => {
const enabled = overlay.querySelector('#mt-set-enabled').checked;
const auto = overlay.querySelector('#mt-set-auto').checked;
const force = overlay.querySelector('#mt-set-force').checked;
const smartAuto = overlay.querySelector('#mt-set-smart-auto').checked;
const threshold = parseFloat(overlay.querySelector('#mt-set-threshold').value) || 0.8;
const perCheck = overlay.querySelector('#mt-set-per-check').checked;
const ballShow = overlay.querySelector('#mt-set-ball').checked;
const mode = overlay.querySelector('#mt-set-mode').value;
const from = overlay.querySelector('#mt-set-from').value;
const to = overlay.querySelector('#mt-set-to').value;
const batch = parseInt(overlay.querySelector('#mt-set-batch').value, 10) || 800;
const skipLinks = overlay.querySelector('#mt-set-skip-links').checked;
const oldEnabled = getSetting('translationEnabled');
saveSetting('translationEnabled', enabled);
saveSetting('autoTranslate', auto);
saveSetting('forceTranslate', force);
saveSetting('smartAutoTranslate', smartAuto);
saveSetting('autoTranslateThreshold', threshold);
saveSetting('perTextLanguageCheck', perCheck);
saveSetting('showBall', ballShow);
saveSetting('transMode', mode);
saveSetting('sourceLang', from);
saveSetting('targetLang', to);
saveSetting('batchSize', batch);
saveSetting('skipLinks', skipLinks);
if (ballShow) {
if (!container) createBall();
} else {
removeBall();
}
if (!enabled && oldEnabled) {
restoreOriginalTexts();
}
overlay.remove();
updateUI();
if (enabled && auto && translatedNodes.size === 0) {
setTimeout(translatePageBatch, 500);
}
});
overlay.addEventListener('click', (e) => {
if (e.target === overlay) overlay.remove();
});
}
// ---------- 页面切换监听 ----------
let pageChangeTimer = null;
function handlePossiblePageChange() {
if (pageChangeTimer) clearTimeout(pageChangeTimer);
pageChangeTimer = setTimeout(() => {
pageChangeTimer = null;
if (!getSetting('translationEnabled')) return;
fullReset();
if (getSetting('autoTranslate')) {
setTimeout(translatePageBatch, 500);
}
}, 200);
}
const origPushState = history.pushState;
history.pushState = function(...args) {
origPushState.apply(this, args);
handlePossiblePageChange();
};
const origReplaceState = history.replaceState;
history.replaceState = function(...args) {
origReplaceState.apply(this, args);
handlePossiblePageChange();
};
window.addEventListener('popstate', handlePossiblePageChange);
window.addEventListener('hashchange', handlePossiblePageChange);
// ---------- 油猴菜单 ----------
GM_registerMenuCommand('启用/禁用翻译', toggleTranslationEnabled);
GM_registerMenuCommand('切换自动翻译', () => {
const val = !getSetting('autoTranslate');
saveSetting('autoTranslate', val);
showToast('自动翻译: ' + (val ? '开' : '关'));
updateUI();
});
GM_registerMenuCommand('切换翻译模式', () => {
const cur = getSetting('transMode');
const newMode = cur === 'replace' ? 'append' : 'replace';
saveSetting('transMode', newMode);
showToast('翻译模式: ' + (newMode === 'replace' ? '替换原文' : '补充翻译'));
updateUI();
});
GM_registerMenuCommand('显示/隐藏悬浮球', () => {
const show = !getSetting('showBall');
saveSetting('showBall', show);
if (show) {
if (!container) createBall();
showToast('悬浮球已显示');
} else {
removeBall();
showToast('悬浮球已隐藏');
}
});
GM_registerMenuCommand('切换纯文本网址跳过', () => {
const val = !getSetting('skipLinks');
saveSetting('skipLinks', val);
showToast('跳过纯文本网址: ' + (val ? '开' : '关'));
});
GM_registerMenuCommand('复位悬浮球位置', resetBallPosition);
GM_registerMenuCommand('插件设置', openSettings);
// ---------- 初始化 ----------
function init() {
if (!document.body) {
document.addEventListener('DOMContentLoaded', init);
return;
}
if (getSetting('showBall')) createBall();
if (getSetting('autoTranslate') && getSetting('translationEnabled')) {
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', () => setTimeout(translatePageBatch, 800));
} else {
setTimeout(translatePageBatch, 800);
}
}
}
init();
})();