// Popup script for managing rules (Firefox version) let currentRules = []; let editingRuleIndex = -1; let ruleModal; // Initialize document.addEventListener('DOMContentLoaded', () => { // Wait for Bootstrap to be fully loaded if (typeof bootstrap !== 'undefined') { initializeExtension(); } else { // Fallback: wait a bit for Bootstrap to load setTimeout(initializeExtension, 100); } }); function initializeExtension() { try { ruleModal = new bootstrap.Modal(document.getElementById('ruleModal')); } catch (e) { console.error('Error initializing modal:', e); } loadRules(); setupEventListeners(); } function setupEventListeners() { const addRuleBtn = document.getElementById('addRuleBtn'); const saveRuleBtn = document.getElementById('saveRuleBtn'); const matchTypeSelect = document.getElementById('matchType'); if (addRuleBtn) { addRuleBtn.addEventListener('click', () => { console.log('Add Rule button clicked'); openRuleModal(); }); } else { console.error('Add Rule button not found!'); } if (saveRuleBtn) { saveRuleBtn.addEventListener('click', saveRule); } else { console.error('Save Rule button not found!'); } if (matchTypeSelect) { matchTypeSelect.addEventListener('change', (e) => { updateFieldVisibility(e.target.value); }); } else { console.error('Match Type select not found!'); } } function updateFieldVisibility(matchType) { const urlGroup = document.getElementById('urlPatternGroup'); const elementGroup = document.getElementById('elementSelectorGroup'); const urlInput = document.getElementById('urlPattern'); const elementInput = document.getElementById('elementSelector'); if (matchType === 'url') { urlGroup.style.display = 'block'; elementGroup.style.display = 'none'; urlInput.required = true; elementInput.required = false; } else if (matchType === 'element') { urlGroup.style.display = 'none'; elementGroup.style.display = 'block'; urlInput.required = false; elementInput.required = true; } else if (matchType === 'both') { urlGroup.style.display = 'block'; elementGroup.style.display = 'block'; urlInput.required = true; elementInput.required = true; } } function loadRules() { browser.storage.sync.get(['rules']).then((result) => { currentRules = result.rules || []; renderRules(); }); } function renderRules() { const rulesList = document.getElementById('rulesList'); const emptyState = document.getElementById('emptyState'); if (currentRules.length === 0) { rulesList.innerHTML = ''; emptyState.style.display = 'block'; return; } emptyState.style.display = 'none'; rulesList.innerHTML = currentRules.map((rule, index) => { const matchTypeLabel = { 'url': 'URL', 'element': 'Element', 'both': 'URL + Element' }[rule.matchType] || rule.matchType; const hasJS = rule.javascript && rule.javascript.trim(); const hasCSS = rule.css && rule.css.trim(); return `
${escapeHtml(rule.name)} ${matchTypeLabel} ${hasJS ? 'JS' : ''} ${hasCSS ? 'CSS' : ''}
${rule.matchType === 'url' || rule.matchType === 'both' ? `
URL: ${escapeHtml(rule.urlPattern)}
` : ''} ${rule.matchType === 'element' || rule.matchType === 'both' ? `
Element: ${escapeHtml(rule.elementSelector)}
` : ''}
`; }).join(''); // Add event listeners using event delegation attachRuleEventListeners(); } function attachRuleEventListeners() { const rulesList = document.getElementById('rulesList'); // Remove old listeners if any rulesList.removeEventListener('click', handleRuleClick); rulesList.removeEventListener('change', handleRuleToggle); // Add new listeners rulesList.addEventListener('click', handleRuleClick); rulesList.addEventListener('change', handleRuleToggle); } function handleRuleClick(e) { const editBtn = e.target.closest('.btn-edit-rule'); const deleteBtn = e.target.closest('.btn-delete-rule'); if (editBtn) { const index = parseInt(editBtn.dataset.index); editRule(index); } else if (deleteBtn) { const index = parseInt(deleteBtn.dataset.index); deleteRule(index); } } function handleRuleToggle(e) { if (e.target.classList.contains('rule-toggle')) { const index = parseInt(e.target.dataset.index); toggleRule(index); } } function openRuleModal(ruleIndex = -1) { editingRuleIndex = ruleIndex; const modalTitle = document.getElementById('modalTitle'); const form = document.getElementById('ruleForm'); form.reset(); if (ruleIndex >= 0) { modalTitle.textContent = 'Edit Rule'; const rule = currentRules[ruleIndex]; document.getElementById('ruleName').value = rule.name; document.getElementById('matchType').value = rule.matchType; document.getElementById('urlPattern').value = rule.urlPattern || ''; document.getElementById('elementSelector').value = rule.elementSelector || ''; document.getElementById('javascript').value = rule.javascript || ''; document.getElementById('css').value = rule.css || ''; document.getElementById('ruleEnabled').checked = rule.enabled; } else { modalTitle.textContent = 'Add Rule'; document.getElementById('ruleEnabled').checked = true; } updateFieldVisibility(document.getElementById('matchType').value); // Show modal - ensure Bootstrap Modal is initialized if (ruleModal) { ruleModal.show(); } else { // Fallback: try to initialize and show try { ruleModal = new bootstrap.Modal(document.getElementById('ruleModal')); ruleModal.show(); } catch (e) { console.error('Error showing modal:', e); alert('Error opening rule editor. Please reload the extension.'); } } } function saveRule() { const name = document.getElementById('ruleName').value.trim(); const matchType = document.getElementById('matchType').value; const urlPattern = document.getElementById('urlPattern').value.trim(); const elementSelector = document.getElementById('elementSelector').value.trim(); const javascript = document.getElementById('javascript').value; const css = document.getElementById('css').value; const enabled = document.getElementById('ruleEnabled').checked; // Validation if (!name) { alert('Please enter a rule name'); return; } if (matchType === 'url' && !urlPattern) { alert('Please enter a URL pattern'); return; } if (matchType === 'element' && !elementSelector) { alert('Please enter an element selector'); return; } if (matchType === 'both' && (!urlPattern || !elementSelector)) { alert('Please enter both URL pattern and element selector'); return; } if (!javascript && !css) { alert('Please enter either JavaScript or CSS code'); return; } const rule = { name, matchType, urlPattern, elementSelector, javascript, css, enabled }; if (editingRuleIndex >= 0) { currentRules[editingRuleIndex] = rule; } else { currentRules.push(rule); } browser.storage.sync.set({ rules: currentRules }).then(() => { loadRules(); ruleModal.hide(); }); } function editRule(index) { openRuleModal(index); } function deleteRule(index) { if (confirm(`Delete rule "${currentRules[index].name}"?`)) { currentRules.splice(index, 1); browser.storage.sync.set({ rules: currentRules }).then(() => { loadRules(); }); } } function toggleRule(index) { currentRules[index].enabled = !currentRules[index].enabled; browser.storage.sync.set({ rules: currentRules }).then(() => { loadRules(); }); } function escapeHtml(text) { const div = document.createElement('div'); div.textContent = text; return div.innerHTML; }