// ==================== СКРИПТ СТРАНИЦЫ НАСТРОЕК ==================== function getStr(path) { const o = window.CAPS_STRINGS || {}; const val = path.split('.').reduce((acc, k) => acc && acc[k], o); return (val !== undefined && val !== null) ? val : path; } function applyOptionsStrings() { document.querySelectorAll('[data-i18n]').forEach((node) => { const key = node.getAttribute('data-i18n'); const text = getStr(key); if (text === '') { node.style.display = 'none'; } else if (text) { node.textContent = text; } }); document.querySelectorAll('[data-i18n-placeholder]').forEach((node) => { const key = node.getAttribute('data-i18n-placeholder'); const text = getStr(key); if (text !== undefined && text !== null) node.placeholder = text; }); const pageTitle = getStr('options.pageTitle'); if (pageTitle) document.title = pageTitle; // Версия — из manifest.json (единый источник) const versionEl = document.getElementById('app-version'); if (versionEl && typeof chrome !== 'undefined' && chrome.runtime && chrome.runtime.getManifest) { const manifest = chrome.runtime.getManifest(); if (manifest && manifest.version) versionEl.textContent = manifest.version; } } // Значения по умолчанию const DEFAULT_CONFIG = { debug: { enabled: true, modules: { core: true, video: true, mnemo: true, close: true, content: true, novnc: true, autologin: true } }, ports: { video: '5000', scheme: '8080' }, novnc: { mode: 'button', redirectDelay: 500 }, mnemo: { mode: 'host-port', skipOnDomain: false, addVideoButton: true, addSchemeButton: true }, autologin: { enabled: false, username: '', password: '', autoSubmit: true, delay: 500 }, disabledSites: [], replaceLogo: true }; // Элементы формы const elements = { // Порты portVideo: document.getElementById('port-video'), portScheme: document.getElementById('port-scheme'), // noVNC (страница экрана) novncRedirect: document.getElementById('novnc-redirect'), redirectDelay: document.getElementById('redirect-delay'), redirectDelayContainer: document.getElementById('redirect-delay-container'), // Мнемосхема mnemoMode: document.getElementById('mnemo-mode'), mnemoSkipOnDomain: document.getElementById('mnemo-skip-on-domain'), mnemoAddSchemeButton: document.getElementById('mnemo-add-scheme-button'), mnemoAddVideoButton: document.getElementById('mnemo-add-video-button'), // Замена логотипа replaceLogo: document.getElementById('replace-logo'), // Автологин autologinEnabled: document.getElementById('autologin-enabled'), autologinSettings: document.getElementById('autologin-settings'), autologinUsername: document.getElementById('autologin-username'), autologinPassword: document.getElementById('autologin-password'), autologinAutoSubmit: document.getElementById('autologin-autosubmit'), autologinDelay: document.getElementById('autologin-delay'), // Отладка debugEnabled: document.getElementById('debug-enabled'), debugModules: document.getElementById('debug-modules'), debugCore: document.getElementById('debug-core'), debugVideo: document.getElementById('debug-video'), debugMnemo: document.getElementById('debug-mnemo'), debugClose: document.getElementById('debug-close'), debugContent: document.getElementById('debug-content'), debugNovnc: document.getElementById('debug-novnc'), debugAutologin: document.getElementById('debug-autologin'), // Кнопки saveBtn: document.getElementById('save-btn'), resetBtn: document.getElementById('reset-btn'), // Статус status: document.getElementById('status') }; // Загрузка настроек при открытии страницы (сначала подставляем строки из strings.js) document.addEventListener('DOMContentLoaded', () => { applyOptionsStrings(); loadSettings(); }); // Обработчики событий elements.saveBtn.addEventListener('click', saveSettings); elements.resetBtn.addEventListener('click', resetSettings); elements.debugEnabled.addEventListener('change', toggleDebugModules); elements.novncRedirect.addEventListener('change', toggleRedirectDelay); elements.autologinEnabled.addEventListener('change', toggleAutologinSettings); // Загрузка сохранённых настроек function loadSettings() { console.log('Загрузка настроек...'); chrome.storage.sync.get(['config'], (result) => { if (chrome.runtime.lastError) { console.error('Ошибка загрузки:', chrome.runtime.lastError); showStatus(getStr('options.statusLoadError') + ' ' + chrome.runtime.lastError.message, 'error'); return; } const config = result.config || DEFAULT_CONFIG; console.log('Настройки получены из storage:', result); console.log('Используемая конфигурация:', config); // Порты elements.portVideo.value = config.ports?.video || DEFAULT_CONFIG.ports.video; elements.portScheme.value = config.ports?.scheme || DEFAULT_CONFIG.ports.scheme; // noVNC elements.novncRedirect.checked = (config.novnc?.mode || DEFAULT_CONFIG.novnc.mode) === 'redirect'; elements.redirectDelay.value = config.novnc?.redirectDelay || DEFAULT_CONFIG.novnc.redirectDelay; // Мнемосхема const mnemoMode = config.mnemo?.mode; const mnemoSkip = config.mnemo?.skipOnDomain === true || mnemoMode === 'skip-on-domain'; elements.mnemoMode.value = (mnemoMode === 'ip-scheme' ? 'host-scheme' : (mnemoMode === 'skip-on-domain' || mnemoMode === 'default' ? 'host-port' : (mnemoMode || 'host-port'))); elements.mnemoSkipOnDomain.checked = mnemoSkip; elements.mnemoAddSchemeButton.checked = config.mnemo?.addSchemeButton !== false; elements.mnemoAddVideoButton.checked = config.mnemo?.addVideoButton !== false; // Замена логотипа elements.replaceLogo.checked = config.replaceLogo !== false; // Автологин elements.autologinEnabled.checked = config.autologin?.enabled || false; elements.autologinUsername.value = config.autologin?.username || ''; elements.autologinPassword.value = config.autologin?.password || ''; elements.autologinAutoSubmit.checked = config.autologin?.autoSubmit !== false; elements.autologinDelay.value = config.autologin?.delay || DEFAULT_CONFIG.autologin.delay; // Отладка elements.debugEnabled.checked = config.debug?.enabled !== false; elements.debugCore.checked = config.debug?.modules?.core !== false; elements.debugVideo.checked = config.debug?.modules?.video !== false; elements.debugMnemo.checked = config.debug?.modules?.mnemo !== false; elements.debugClose.checked = config.debug?.modules?.close !== false; elements.debugContent.checked = config.debug?.modules?.content !== false; elements.debugNovnc.checked = config.debug?.modules?.novnc !== false; elements.debugAutologin.checked = config.debug?.modules?.autologin !== false; // Обновляем UI toggleDebugModules(); toggleRedirectDelay(); toggleAutologinSettings(); console.log('✅ Настройки загружены успешно'); }); } // Сохранение настроек function saveSettings() { // Валидация портов const portVideo = elements.portVideo.value.trim(); const portScheme = elements.portScheme.value.trim(); if (!portVideo || isNaN(portVideo) || portVideo < 1 || portVideo > 65535) { showStatus(getStr('options.errorPortVideo'), 'error'); return; } if (!portScheme || isNaN(portScheme) || portScheme < 1 || portScheme > 65535) { showStatus(getStr('options.errorPortScheme'), 'error'); return; } const redirectDelay = parseInt(elements.redirectDelay.value) || 500; const autologinDelay = parseInt(elements.autologinDelay.value) || 500; // Собираем конфигурацию const config = { debug: { enabled: elements.debugEnabled.checked, modules: { core: elements.debugCore.checked, video: elements.debugVideo.checked, mnemo: elements.debugMnemo.checked, close: elements.debugClose.checked, content: elements.debugContent.checked, novnc: elements.debugNovnc.checked, autologin: elements.debugAutologin.checked } }, ports: { video: portVideo, scheme: portScheme }, novnc: { mode: elements.novncRedirect.checked ? 'redirect' : 'button', redirectDelay: redirectDelay }, mnemo: { mode: elements.mnemoMode.value, skipOnDomain: elements.mnemoSkipOnDomain.checked, addVideoButton: elements.mnemoAddVideoButton.checked, addSchemeButton: elements.mnemoAddSchemeButton.checked }, replaceLogo: elements.replaceLogo.checked, autologin: { enabled: elements.autologinEnabled.checked, username: elements.autologinUsername.value.trim(), password: elements.autologinPassword.value, autoSubmit: elements.autologinAutoSubmit.checked, delay: autologinDelay } }; // Сохраняем список отключённых сайтов из текущего storage chrome.storage.sync.get(['config'], (prev) => { if (prev.config && Array.isArray(prev.config.disabledSites)) { config.disabledSites = prev.config.disabledSites; } else { config.disabledSites = []; } // Сохраняем в chrome.storage chrome.storage.sync.set({ config }, () => { if (chrome.runtime.lastError) { console.error('Ошибка сохранения:', chrome.runtime.lastError); showStatus(getStr('options.statusSaveError') + ' ' + chrome.runtime.lastError.message, 'error'); return; } console.log('Настройки сохранены:', config); showStatus(getStr('options.statusSaveOk'), 'success'); // Отправляем сообщение всем вкладкам для обновления конфига chrome.tabs.query({}, (tabs) => { tabs.forEach(tab => { chrome.tabs.sendMessage(tab.id, { type: 'CONFIG_UPDATED', config: config }, (response) => { // Игнорируем ошибки для вкладок, где нет content script if (chrome.runtime.lastError) { // Это нормально, не все вкладки имеют content script } }); }); }); }); }); } // Сброс настроек к значениям по умолчанию function resetSettings() { if (!confirm(getStr('options.confirmReset'))) { return; } // Устанавливаем значения по умолчанию elements.portVideo.value = DEFAULT_CONFIG.ports.video; elements.portScheme.value = DEFAULT_CONFIG.ports.scheme; elements.novncRedirect.checked = DEFAULT_CONFIG.novnc.mode === 'redirect'; elements.redirectDelay.value = DEFAULT_CONFIG.novnc.redirectDelay; elements.mnemoMode.value = DEFAULT_CONFIG.mnemo.mode; elements.mnemoSkipOnDomain.checked = DEFAULT_CONFIG.mnemo.skipOnDomain; elements.mnemoAddSchemeButton.checked = DEFAULT_CONFIG.mnemo.addSchemeButton; elements.mnemoAddVideoButton.checked = DEFAULT_CONFIG.mnemo.addVideoButton; elements.replaceLogo.checked = DEFAULT_CONFIG.replaceLogo !== false; elements.autologinEnabled.checked = DEFAULT_CONFIG.autologin.enabled; elements.autologinUsername.value = DEFAULT_CONFIG.autologin.username; elements.autologinPassword.value = DEFAULT_CONFIG.autologin.password; elements.autologinAutoSubmit.checked = DEFAULT_CONFIG.autologin.autoSubmit; elements.autologinDelay.value = DEFAULT_CONFIG.autologin.delay; elements.debugEnabled.checked = DEFAULT_CONFIG.debug.enabled; elements.debugCore.checked = DEFAULT_CONFIG.debug.modules.core; elements.debugVideo.checked = DEFAULT_CONFIG.debug.modules.video; elements.debugMnemo.checked = DEFAULT_CONFIG.debug.modules.mnemo; elements.debugClose.checked = DEFAULT_CONFIG.debug.modules.close; elements.debugContent.checked = DEFAULT_CONFIG.debug.modules.content; elements.debugNovnc.checked = DEFAULT_CONFIG.debug.modules.novnc; elements.debugAutologin.checked = DEFAULT_CONFIG.debug.modules.autologin; // Сохраняем chrome.storage.sync.set({ config: DEFAULT_CONFIG }, () => { console.log('Настройки сброшены к значениям по умолчанию'); showStatus(getStr('options.statusResetDone'), 'success'); toggleDebugModules(); toggleRedirectDelay(); toggleAutologinSettings(); }); } // Показать/скрыть модули отладки (при загрузке без .expanded блок изначально скрыт) function toggleDebugModules() { if (elements.debugEnabled.checked) { elements.debugModules.classList.add('expanded'); } else { elements.debugModules.classList.remove('expanded'); } } // Показать/скрыть поле задержки переадресации function toggleRedirectDelay() { if (elements.novncRedirect.checked) { elements.redirectDelayContainer.style.display = 'block'; } else { elements.redirectDelayContainer.style.display = 'none'; } } // Показать/скрыть настройки автологина function toggleAutologinSettings() { if (elements.autologinEnabled.checked) { elements.autologinSettings.classList.remove('disabled'); } else { elements.autologinSettings.classList.add('disabled'); } } // Показать статус сообщение function showStatus(message, type = 'success') { elements.status.textContent = message; elements.status.className = `status ${type}`; elements.status.classList.remove('hidden'); // Автоматически скрыть через 5 секунд setTimeout(() => { elements.status.classList.add('hidden'); }, 5000); } // Валидация при вводе (только цифры для портов) elements.portVideo.addEventListener('input', (e) => { e.target.value = e.target.value.replace(/[^0-9]/g, ''); }); elements.portScheme.addEventListener('input', (e) => { e.target.value = e.target.value.replace(/[^0-9]/g, ''); }); // Тестирование chrome.storage при загрузке страницы console.log('=== Проверка chrome.storage API ==='); console.log('chrome.storage доступен:', typeof chrome.storage !== 'undefined'); console.log('chrome.storage.sync доступен:', typeof chrome.storage?.sync !== 'undefined'); // Тестовое сохранение и чтение if (typeof chrome.storage !== 'undefined' && chrome.storage.sync) { chrome.storage.sync.set({ test: 'test_value' }, () => { if (chrome.runtime.lastError) { console.error('❌ Тест сохранения FAILED:', chrome.runtime.lastError); } else { console.log('✅ Тест сохранения OK'); chrome.storage.sync.get(['test'], (result) => { if (chrome.runtime.lastError) { console.error('❌ Тест чтения FAILED:', chrome.runtime.lastError); } else { console.log('✅ Тест чтения OK:', result); } }); } }); } else { console.error('❌ chrome.storage.sync недоступен!'); }