const listSelect = document.getElementById('listSelect'); const listName = document.getElementById('listName'); const listBg = document.getElementById('listBg'); const listFg = document.getElementById('listFg'); const listActive = document.getElementById('listActive'); const bulkPaste = document.getElementById('bulkPaste'); const wordList = document.getElementById('wordList'); const importInput = document.getElementById('importInput'); const matchCase = document.getElementById('matchCase'); const matchWhole = document.getElementById('matchWhole'); let lists = []; let currentListIndex = 0; let selectedCheckboxes = new Set(); let globalHighlightEnabled = true; let wordSearchQuery = ''; let matchCaseEnabled = false; let matchWholeEnabled = false; let exceptionsList = []; let currentTabHost = ''; let sectionStates = {}; function loadSectionStates() { const saved = localStorage.getItem('goose-highlighter-section-states'); if (saved) { try { sectionStates = JSON.parse(saved); } catch { sectionStates = {}; } } } function saveSectionStates() { localStorage.setItem('goose-highlighter-section-states', JSON.stringify(sectionStates)); } function toggleSection(sectionName) { const section = document.querySelector(`[data-section="${sectionName}"]`); if (!section) return; const isCollapsed = section.classList.contains('collapsed'); if (isCollapsed) { section.classList.remove('collapsed'); sectionStates[sectionName] = false; } else { section.classList.add('collapsed'); sectionStates[sectionName] = true; } saveSectionStates(); } function initializeSectionStates() { loadSectionStates(); // Apply saved states Object.keys(sectionStates).forEach(sectionName => { const section = document.querySelector(`[data-section="${sectionName}"]`); if (section && sectionStates[sectionName]) { section.classList.add('collapsed'); } }); } function escapeHtml(str) { return str.replace(/[&<>"']/g, function (m) { return ({ '&': '&', '<': '<', '>': '>', '"': '"', '\'': ''' })[m]; }); } async function save() { await chrome.storage.local.set({ lists: lists, globalHighlightEnabled: globalHighlightEnabled, matchCaseEnabled, matchWholeEnabled, exceptionsList }); renderLists(); renderWords(); chrome.tabs.query({}, function (tabs) { for (let tab of tabs) { if (tab.id) { chrome.tabs.sendMessage(tab.id, { type: 'WORD_LIST_UPDATED' }); chrome.tabs.sendMessage(tab.id, { type: 'GLOBAL_TOGGLE_UPDATED', enabled: globalHighlightEnabled }); chrome.tabs.sendMessage(tab.id, { type: 'MATCH_OPTIONS_UPDATED', matchCase: matchCaseEnabled, matchWhole: matchWholeEnabled }); chrome.tabs.sendMessage(tab.id, { type: 'EXCEPTIONS_LIST_UPDATED' }); } } }); } async function updateGlobalToggleState() { await chrome.storage.local.set({ globalHighlightEnabled: globalHighlightEnabled }); chrome.tabs.query({}, function (tabs) { for (let tab of tabs) { if (tab.id) { chrome.tabs.sendMessage(tab.id, { type: 'GLOBAL_TOGGLE_UPDATED', enabled: globalHighlightEnabled }); } } }); } async function load() { const res = await chrome.storage.local.get({ lists: [], globalHighlightEnabled: true, matchCaseEnabled: false, matchWholeEnabled: false, exceptionsList: [] }); lists = res.lists; globalHighlightEnabled = res.globalHighlightEnabled !== false; matchCaseEnabled = !!res.matchCaseEnabled; matchWholeEnabled = !!res.matchWholeEnabled; exceptionsList = res.exceptionsList || []; matchCase.checked = matchCaseEnabled; matchWhole.checked = matchWholeEnabled; try { const [tab] = await chrome.tabs.query({ active: true, currentWindow: true }); if (tab && tab.url) { const url = new URL(tab.url); currentTabHost = url.hostname; updateExceptionButton(); } } catch (e) { console.warn('Could not get current tab:', e); } if (!lists.length) { lists.push({ id: Date.now(), name: chrome.i18n.getMessage('default_list_name'), background: '#ffff00', foreground: '#000000', active: true, words: [] }); } renderLists(); renderWords(); renderExceptions(); document.getElementById('globalHighlightToggle').checked = globalHighlightEnabled; } function renderLists() { listSelect.innerHTML = lists.map((list, index) => `` ).join(''); listSelect.value = currentListIndex; updateListForm(); } function updateListForm() { const list = lists[currentListIndex]; listName.value = list.name; listBg.value = list.background; listFg.value = list.foreground; listActive.checked = list.active; } function renderWords() { const list = lists[currentListIndex]; let filteredWords = list.words; if (wordSearchQuery.trim()) { const q = wordSearchQuery.trim().toLowerCase(); filteredWords = list.words.filter(w => w.wordStr.toLowerCase().includes(q)); } const itemHeight = 32; const containerHeight = wordList.clientHeight; const scrollTop = wordList.scrollTop; const startIndex = Math.floor(scrollTop / itemHeight); const endIndex = Math.min( startIndex + Math.ceil(containerHeight / itemHeight) + 2, filteredWords.length ); wordList.innerHTML = ''; const spacer = document.createElement('div'); spacer.style.position = 'relative'; spacer.style.height = `${filteredWords.length * itemHeight}px`; spacer.style.width = '100%'; for (let i = startIndex; i < endIndex; i++) { const w = filteredWords[i]; if (!w) continue; const container = document.createElement('div'); container.style.height = `${itemHeight}px`; container.style.position = 'absolute'; container.style.top = `${i * itemHeight}px`; container.style.width = 'calc(100% - 8px)'; container.style.left = '4px'; container.style.right = '4px'; container.style.display = 'flex'; container.style.alignItems = 'center'; container.style.gap = '6px'; container.style.padding = '0 4px'; container.style.boxSizing = 'border-box'; container.style.background = 'var(--highlight-tag)'; container.style.border = '1px solid var(--highlight-tag-border)'; const realIndex = list.words.indexOf(w); const cbSelect = document.createElement('input'); cbSelect.type = 'checkbox'; cbSelect.className = 'word-checkbox'; cbSelect.dataset.index = realIndex; if (selectedCheckboxes.has(realIndex)) { cbSelect.checked = true; } const inputWord = document.createElement('input'); inputWord.type = 'text'; inputWord.value = w.wordStr; inputWord.dataset.wordEdit = realIndex; inputWord.style.flexGrow = '1'; inputWord.style.minWidth = '0'; inputWord.style.padding = '4px 8px'; inputWord.style.borderRadius = '4px'; inputWord.style.border = '1px solid var(--input-border)'; inputWord.style.backgroundColor = 'var(--input-bg)'; inputWord.style.color = 'var(--text-color)'; const inputBg = document.createElement('input'); inputBg.type = 'color'; inputBg.value = w.background || list.background; inputBg.dataset.bgEdit = realIndex; inputBg.style.width = '24px'; inputBg.style.height = '24px'; inputBg.style.flexShrink = '0'; const inputFg = document.createElement('input'); inputFg.type = 'color'; inputFg.value = w.foreground || list.foreground; inputFg.dataset.fgEdit = realIndex; inputFg.style.width = '24px'; inputFg.style.height = '24px'; inputFg.style.flexShrink = '0'; const activeContainer = document.createElement('label'); activeContainer.className = 'word-active'; activeContainer.style.display = 'flex'; activeContainer.style.alignItems = 'center'; activeContainer.style.gap = '4px'; activeContainer.style.flexShrink = '0'; const cbActive = document.createElement('input'); cbActive.type = 'checkbox'; cbActive.checked = w.active !== false; cbActive.dataset.activeEdit = realIndex; cbActive.className = 'switch'; activeContainer.appendChild(cbActive); container.appendChild(cbSelect); container.appendChild(inputWord); container.appendChild(inputBg); container.appendChild(inputFg); container.appendChild(activeContainer); spacer.appendChild(container); } wordList.appendChild(spacer); const wordCount = document.getElementById('wordCount'); if (wordCount) { wordCount.textContent = filteredWords.length; } } function updateExceptionButton() { const toggleBtn = document.getElementById('toggleExceptionBtn'); const btnText = document.getElementById('exceptionBtnText'); if (!toggleBtn || !btnText || !currentTabHost) return; const isException = exceptionsList.includes(currentTabHost); if (isException) { btnText.textContent = chrome.i18n.getMessage('remove_exception') || 'Remove from Exceptions'; toggleBtn.className = 'danger'; toggleBtn.querySelector('i').className = 'fa-solid fa-check'; } else { btnText.textContent = chrome.i18n.getMessage('add_exception') || 'Add to Exceptions'; toggleBtn.className = ''; toggleBtn.querySelector('i').className = 'fa-solid fa-ban'; } } function renderExceptions() { const container = document.getElementById('exceptionsList'); if (!container) return; if (exceptionsList.length === 0) { container.innerHTML = '