} tally Per-host block counts (`ellyBlockTallyByHost` in sync storage).
*/
function loadTopSites(tally) {
const topSitesList = document.getElementById('topSitesList');
if (!topSitesList) {
return;
}
const rows = getTopBlockedSitesForUi(tally, 10);
if (rows.length === 0) {
topSitesList.innerHTML =
'No per-site data yet. Counts appear as Elly blocks tabs by policy.
';
return;
}
topSitesList.innerHTML = rows
.map(
(r, i) => `
${i + 1}. ${escapeHtmlForUi(r.host)}
${r.count} blocks
`
)
.join('');
}
function exportStatistics() {
chrome.storage.sync.get(['statistics'], (data) => {
const csv = convertToCSV(data.statistics);
const blob = new Blob([csv], { type: 'text/csv' });
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = `nanny-stats-${new Date().toISOString().split('T')[0]}.csv`;
document.body.appendChild(a);
a.click();
document.body.removeChild(a);
URL.revokeObjectURL(url);
});
}
function convertToCSV(stats) {
const rows = [['Date', 'Blocks', 'Time Saved (seconds)', 'Time Saved (hours)']];
for (const [date, data] of Object.entries(stats)) {
rows.push([
date,
data.blocks || 0,
data.timeSaved || 0,
Math.floor((data.timeSaved || 0) / 3600)
]);
}
return rows.map(row => row.join(',')).join('\n');
}
async function clearStatistics() {
const ok = await requireParentPinOk(
'Enter your parent override PIN to clear all statistics.',
'Your parental Pin is required to remove stats.'
);
if (!ok) {
return;
}
await chrome.storage.sync.set({ statistics: {}, ellyBlockTallyByHost: {} });
loadStatistics();
showEllyToast('Statistics cleared.', 'success');
}
async function saveAllSettings() {
try {
// Gather all settings from the UI
const currentData = await chrome.storage.sync.get(['settings']);
const prev = currentData.settings || {};
// Security toggles are saved only via dedicated handlers (PIN-gated).
// Preserve stored values here so auto-save cannot bypass Strict Mode / PIN lock.
// Parent PIN: never write overridePIN from the field — use setParentPin / Update PIN only.
const settings = {
strictMode: !!prev.strictMode,
blocklistPinLock: !!(prev.strictMode || prev.blocklistPinLock),
autoCloseTabs: document.getElementById('autoCloseTabs').checked,
showNotifications: document.getElementById('showNotifications').checked,
allowSearchEngineResults: document.getElementById('allowSearchEngineResults').checked,
theme: document.getElementById('themeSelect').value,
pomodoroMinutes: parseInt(document.getElementById('pomodoroMinutes').value),
breakMinutes: parseInt(document.getElementById('breakMinutes').value),
syncFrequency: document.getElementById('syncFrequency').value
};
const updatedSettings = { ...prev, ...settings };
// Never re-persist Parent PIN material from options auto-save.
delete updatedSettings.overridePIN;
delete updatedSettings.overridePinHash;
if (typeof prev.overridePinHash === 'string' && prev.overridePinHash) {
updatedSettings.overridePinHash = prev.overridePinHash;
}
await chrome.storage.sync.set({ settings: updatedSettings });
updateSecurityToggleUi(updatedSettings);
// Update last sync time
document.getElementById('lastSync').textContent =
`Last sync: ${new Date().toLocaleTimeString()}`;
console.log('All settings saved');
} catch (error) {
console.error('Error saving settings:', error);
await openEllyAlertModal({
title: 'Save failed',
message: 'Error saving settings. Please try again.'
});
}
}