fix(settings): rewrite renderPanel to use panel body innerHTML, not document.body
- Replace document.body.innerHTML with panel.querySelector('.settings-popover-body').innerHTML
- Use theme buttons (.theme-btn) with icons instead of radio buttons
- Use .engine-toggle class for engine checkboxes in 2-column grid
- Include settings-notice paragraph for engine changes
- Use dropdowns for safe search and format with proper ids
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
1906723859
commit
8e53a8b11d
1 changed files with 101 additions and 100 deletions
|
|
@ -80,121 +80,122 @@ function openPanel() {
|
||||||
}
|
}
|
||||||
|
|
||||||
function escapeHtml(str) {
|
function escapeHtml(str) {
|
||||||
return str
|
return String(str).replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>');
|
||||||
.replace(/&/g, '&')
|
|
||||||
.replace(/</g, '<')
|
|
||||||
.replace(/>/g, '>');
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function renderPanel(prefs) {
|
function renderPanel(prefs) {
|
||||||
var themeIcons = { light: '☀️', dark: '🌙', system: '⌨' };
|
var panel = document.getElementById('settings-popover');
|
||||||
var safeOptions = ['moderate', 'strict', 'off'];
|
if (!panel) return;
|
||||||
var formatOptions = ['html', 'json', 'csv', 'rss'];
|
var body = panel.querySelector('.settings-popover-body');
|
||||||
|
if (!body) return;
|
||||||
|
|
||||||
var html = '<div id="settings-panel-inner">';
|
var themeBtns = '';
|
||||||
html += '<h2>Settings</h2>';
|
['light', 'dark', 'system'].forEach(function(t) {
|
||||||
|
var icons = { light: '\u2600', dark: '\u263D', system: '\u2318' };
|
||||||
|
var labels = { light: 'Light', dark: 'Dark', system: 'System' };
|
||||||
|
var active = prefs.theme === t ? ' active' : '';
|
||||||
|
themeBtns += '<button class="theme-btn' + active + '" data-theme="' + t + '">' + icons[t] + ' ' + labels[t] + '</button>';
|
||||||
|
});
|
||||||
|
|
||||||
|
var engineToggles = '';
|
||||||
|
ALL_ENGINES.forEach(function(name) {
|
||||||
|
var checked = prefs.engines.indexOf(name) !== -1 ? ' checked' : '';
|
||||||
|
engineToggles += '<label class="engine-toggle"><input type="checkbox" value="' + escapeHtml(name) + '"' + checked + '><span>' + escapeHtml(name) + '</span></label>';
|
||||||
|
});
|
||||||
|
|
||||||
|
var ssOptions = [
|
||||||
|
{ val: 'moderate', label: 'Moderate' },
|
||||||
|
{ val: 'strict', label: 'Strict' },
|
||||||
|
{ val: 'off', label: 'Off' }
|
||||||
|
];
|
||||||
|
var fmtOptions = [
|
||||||
|
{ val: 'html', label: 'HTML' },
|
||||||
|
{ val: 'json', label: 'JSON' },
|
||||||
|
{ val: 'csv', label: 'CSV' },
|
||||||
|
{ val: 'rss', label: 'RSS' }
|
||||||
|
];
|
||||||
|
var ssOptionsHtml = '';
|
||||||
|
var fmtOptionsHtml = '';
|
||||||
|
ssOptions.forEach(function(o) {
|
||||||
|
var sel = prefs.safeSearch === o.val ? ' selected' : '';
|
||||||
|
ssOptionsHtml += '<option value="' + o.val + '"' + sel + '>' + o.label + '</option>';
|
||||||
|
});
|
||||||
|
fmtOptions.forEach(function(o) {
|
||||||
|
var sel = prefs.format === o.val ? ' selected' : '';
|
||||||
|
fmtOptionsHtml += '<option value="' + o.val + '"' + sel + '>' + o.label + '</option>';
|
||||||
|
});
|
||||||
|
|
||||||
|
body.innerHTML =
|
||||||
|
'<div class="settings-section">' +
|
||||||
|
'<div class="settings-section-title">Appearance</div>' +
|
||||||
|
'<div class="theme-buttons">' + themeBtns + '</div>' +
|
||||||
|
'</div>' +
|
||||||
|
'<div class="settings-section">' +
|
||||||
|
'<div class="settings-section-title">Engines</div>' +
|
||||||
|
'<div class="engine-grid">' + engineToggles + '</div>' +
|
||||||
|
'<p class="settings-notice">Engine changes apply to your next search.</p>' +
|
||||||
|
'</div>' +
|
||||||
|
'<div class="settings-section">' +
|
||||||
|
'<div class="settings-section-title">Search Defaults</div>' +
|
||||||
|
'<div class="setting-row">' +
|
||||||
|
'<label for="pref-safesearch">Safe search</label>' +
|
||||||
|
'<select id="pref-safesearch">' + ssOptionsHtml + '</select>' +
|
||||||
|
'</div>' +
|
||||||
|
'<div class="setting-row">' +
|
||||||
|
'<label for="pref-format">Default format</label>' +
|
||||||
|
'<select id="pref-format">' + fmtOptionsHtml + '</select>' +
|
||||||
|
'</div>' +
|
||||||
|
'</div>';
|
||||||
|
|
||||||
// Theme buttons
|
// Theme buttons
|
||||||
html += '<fieldset><legend>Theme</legend>';
|
var themeBtnEls = panel.querySelectorAll('.theme-btn');
|
||||||
html += '<div class="theme-buttons">';
|
for (var i = 0; i < themeBtnEls.length; i++) {
|
||||||
['light', 'dark', 'system'].forEach(function(t) {
|
themeBtnEls[i].addEventListener('click', (function(btn) {
|
||||||
var checked = prefs.theme === t ? ' checked' : '';
|
return function() {
|
||||||
var icon = escapeHtml(themeIcons[t]);
|
prefs.theme = btn.getAttribute('data-theme');
|
||||||
html += '<label><input type="radio" name="theme" value="' + escapeHtml(t) + '"' + checked + '> ' + icon + ' ' + escapeHtml(t.charAt(0).toUpperCase() + t.slice(1)) + '</label>';
|
savePrefs(prefs);
|
||||||
});
|
applyTheme(prefs.theme);
|
||||||
html += '</div></fieldset>';
|
syncEngineInput(prefs);
|
||||||
|
renderPanel(prefs);
|
||||||
|
};
|
||||||
|
})(themeBtnEls[i]));
|
||||||
|
}
|
||||||
|
|
||||||
// Engine checkboxes
|
// Engine checkboxes
|
||||||
html += '<fieldset><legend>Engines</legend>';
|
var checkboxes = panel.querySelectorAll('.engine-toggle input[type="checkbox"]');
|
||||||
html += '<div class="engine-grid">';
|
for (var j = 0; j < checkboxes.length; j++) {
|
||||||
ALL_ENGINES.forEach(function(engine) {
|
checkboxes[j].addEventListener('change', (function(cb) {
|
||||||
var checked = prefs.engines.indexOf(engine) !== -1 ? ' checked' : '';
|
return function() {
|
||||||
html += '<label><input type="checkbox" name="engine" value="' + escapeHtml(engine) + '"' + checked + '> ' + escapeHtml(engine) + '</label>';
|
var checked = Array.prototype.slice.call(panel.querySelectorAll('.engine-toggle input[type="checkbox"]:checked')).map(function(el) { return el.value; });
|
||||||
});
|
if (checked.length === 0) { renderPanel(prefs); return; }
|
||||||
html += '</div></fieldset>';
|
prefs.engines = checked;
|
||||||
|
savePrefs(prefs);
|
||||||
html += '<p class="notice">Engine changes apply to your next search.</p>';
|
syncEngineInput(prefs);
|
||||||
|
};
|
||||||
// Safe search dropdown
|
})(checkboxes[j]));
|
||||||
html += '<label for="safe-search-select">Safe Search</label>';
|
|
||||||
html += '<select id="safe-search-select">';
|
|
||||||
safeOptions.forEach(function(opt) {
|
|
||||||
var selected = prefs.safeSearch === opt ? ' selected' : '';
|
|
||||||
html += '<option value="' + escapeHtml(opt) + '"' + selected + '>' + escapeHtml(opt.charAt(0).toUpperCase() + opt.slice(1)) + '</option>';
|
|
||||||
});
|
|
||||||
html += '</select>';
|
|
||||||
|
|
||||||
// Format dropdown
|
|
||||||
html += '<label for="format-select">Format</label>';
|
|
||||||
html += '<select id="format-select">';
|
|
||||||
formatOptions.forEach(function(opt) {
|
|
||||||
var selected = prefs.format === opt ? ' selected' : '';
|
|
||||||
html += '<option value="' + escapeHtml(opt) + '"' + selected + '>' + escapeHtml(opt.toUpperCase()) + '</option>';
|
|
||||||
});
|
|
||||||
html += '</select>';
|
|
||||||
|
|
||||||
html += '<button type="button" id="settings-close">Close</button>';
|
|
||||||
html += '</div>';
|
|
||||||
|
|
||||||
document.body.innerHTML = html;
|
|
||||||
|
|
||||||
// Attach listeners to theme buttons
|
|
||||||
var themeButtons = document.querySelectorAll('input[name="theme"]');
|
|
||||||
themeButtons.forEach(function(btn) {
|
|
||||||
btn.addEventListener('click', function() {
|
|
||||||
var newPrefs = loadPrefs();
|
|
||||||
newPrefs.theme = btn.value;
|
|
||||||
savePrefs(newPrefs);
|
|
||||||
applyTheme(newPrefs.theme);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
// Attach listeners to engine checkboxes
|
|
||||||
var engineCheckboxes = document.querySelectorAll('input[name="engine"]');
|
|
||||||
engineCheckboxes.forEach(function(cb) {
|
|
||||||
cb.addEventListener('change', function() {
|
|
||||||
var newPrefs = loadPrefs();
|
|
||||||
if (cb.checked) {
|
|
||||||
if (newPrefs.engines.indexOf(cb.value) === -1) {
|
|
||||||
newPrefs.engines.push(cb.value);
|
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
newPrefs.engines = newPrefs.engines.filter(function(e) { return e !== cb.value; });
|
|
||||||
}
|
|
||||||
if (newPrefs.engines.length === 0) {
|
|
||||||
renderPanel(loadPrefs());
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
savePrefs(newPrefs);
|
|
||||||
syncEngineInput(newPrefs);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
// Attach listener to safe search dropdown
|
// Safe search
|
||||||
var safeSelect = document.getElementById('safe-search-select');
|
var ssEl = panel.querySelector('#pref-safesearch');
|
||||||
if (safeSelect) {
|
if (ssEl) {
|
||||||
safeSelect.addEventListener('change', function() {
|
ssEl.addEventListener('change', function() {
|
||||||
var newPrefs = loadPrefs();
|
prefs.safeSearch = ssEl.value;
|
||||||
newPrefs.safeSearch = safeSelect.value;
|
savePrefs(prefs);
|
||||||
savePrefs(newPrefs);
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// Attach listener to format dropdown
|
// Format
|
||||||
var formatSelect = document.getElementById('format-select');
|
var fmtEl = panel.querySelector('#pref-format');
|
||||||
if (formatSelect) {
|
if (fmtEl) {
|
||||||
formatSelect.addEventListener('change', function() {
|
fmtEl.addEventListener('change', function() {
|
||||||
var newPrefs = loadPrefs();
|
prefs.format = fmtEl.value;
|
||||||
newPrefs.format = formatSelect.value;
|
savePrefs(prefs);
|
||||||
savePrefs(newPrefs);
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// Attach listener to close button
|
// Close button
|
||||||
var closeBtn = document.getElementById('settings-close');
|
var closeBtn = panel.querySelector('.settings-popover-close');
|
||||||
if (closeBtn) {
|
if (closeBtn) closeBtn.addEventListener('click', closePanel);
|
||||||
closeBtn.addEventListener('click', closePanel);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function initSettings() {
|
function initSettings() {
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue