54216aa133
Add persistent site history storage and plumbing between the renderer settings UI and the native app. The app now loads/saves site_history.txt in the user data directory (max 200 entries, http/https-only, stored one URL per line) and records visited sites on navigation. Settings pages receive the history via injected JavaScript when the settings page finishes loading, and a "clear-site-history" message from the settings UI clears the on-disk history and updates the renderer. Other changes: allow settings-related process messages from content frames in the CEF client, introduce OnContentLoadFinished to trigger history injection, expose electronAPI.send/sendToHost (and reuse the native postMessage handler) in the V8 context, and remove the BigPicture in-app history UI/refresh/clear handlers (history is now managed by the native app). Also cleaned up includes and added helper utilities for JSON escaping, lowercasing, and file path handling. The initial tab restore logic was simplified to always create an initial tab (home or initial_url) and persist the session.
603 lines
26 KiB
HTML
603 lines
26 KiB
HTML
<!DOCTYPE html>
|
||
<html lang="en">
|
||
<head>
|
||
<meta charset="UTF-8">
|
||
<title>Settings</title>
|
||
<link rel="stylesheet" href="../css/settings.css" />
|
||
<link rel="icon" href="data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 100 100'><text y='.9em' font-size='90'>⚙️</text></svg>">
|
||
<!-- Inline styles removed; styles now live in settings.css for a cleaner, modern look. -->
|
||
</head>
|
||
<body>
|
||
<div class="container" role="application">
|
||
<aside class="sidebar" aria-label="Settings categories">
|
||
<h1>Settings</h1>
|
||
<nav class="tabs" role="tablist">
|
||
<button class="tab-link active" role="tab" aria-selected="true" aria-controls="panel-general" id="tab-general" data-tab="general">General</button>
|
||
<button class="tab-link" role="tab" aria-selected="false" aria-controls="panel-appearance" id="tab-appearance" data-tab="appearance">Appearance</button>
|
||
<button class="tab-link" role="tab" aria-selected="false" aria-controls="panel-history" id="tab-history" data-tab="history">History</button>
|
||
<button class="tab-link" role="tab" aria-selected="false" aria-controls="panel-plugins" id="tab-plugins" data-tab="plugins">Plugins</button>
|
||
<button class="tab-link" role="tab" aria-selected="false" aria-controls="panel-about" id="tab-about" data-tab="about">About</button>
|
||
</nav>
|
||
</aside>
|
||
|
||
<main class="content">
|
||
<!-- General Panel -->
|
||
<section class="tab-panel active" id="panel-general" role="tabpanel" aria-labelledby="tab-general">
|
||
<h2>General</h2>
|
||
|
||
<div class="setting-group">
|
||
<h3>Data Management</h3>
|
||
<p class="note">Clear all cookies, cache, and browsing data stored locally on this device.</p>
|
||
<div class="setting-row">
|
||
<button id="clear-data-btn">Clear All Data</button>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Big Picture Mode -->
|
||
<div class="setting-group">
|
||
<h3>Big Picture Mode</h3>
|
||
<p class="note">A controller-friendly UI designed for handheld devices (e.g., Steam Deck).</p>
|
||
<div class="setting-row">
|
||
<button id="launch-bigpicture-btn" class="primary-btn">
|
||
<span style="font-size: 18px;"></span> Launch Big Picture Mode
|
||
</button>
|
||
<span id="bigpicture-status" class="note"></span>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="setting-group">
|
||
<h3>Weather Display</h3>
|
||
<p class="note">Choose how temperature is displayed on the Home page weather card.</p>
|
||
<fieldset class="weather-units settings-fieldset">
|
||
<legend>Temperature units</legend>
|
||
<label style="display: block; margin-bottom: 8px;"><input type="radio" name="weather-unit" id="weather-unit-auto" value="auto" checked> Auto (based on locale)</label>
|
||
<label style="display: block; margin-bottom: 8px;"><input type="radio" name="weather-unit" id="weather-unit-c" value="c"> Celsius (°C)</label>
|
||
<label style="display: block; margin-bottom: 8px;"><input type="radio" name="weather-unit" id="weather-unit-f" value="f"> Fahrenheit (°F)</label>
|
||
</fieldset>
|
||
</div>
|
||
|
||
<div class="setting-group">
|
||
<h3>System Information</h3>
|
||
<div class="debug-info" id="debug-info">Loading debug info...</div>
|
||
</div>
|
||
</section>
|
||
|
||
<!-- Appearance Panel -->
|
||
<section class="tab-panel" id="panel-appearance" role="tabpanel" aria-labelledby="tab-appearance">
|
||
<h2>Appearance</h2>
|
||
<!-- Theme Selection -->
|
||
<div class="customization-group">
|
||
<h3>Theme Presets</h3>
|
||
<div class="theme-selector">
|
||
<button id="theme-default" class="theme-btn" data-theme="default">
|
||
<div class="theme-preview" style="background: linear-gradient(145deg, #121418, #1B1035);"></div>
|
||
<span>Default</span>
|
||
</button>
|
||
<button id="theme-ocean" class="theme-btn" data-theme="ocean">
|
||
<div class="theme-preview" style="background: linear-gradient(145deg, #1a365d, #2c5282);"></div>
|
||
<span>Ocean</span>
|
||
</button>
|
||
<button id="theme-forest" class="theme-btn" data-theme="forest">
|
||
<div class="theme-preview" style="background: linear-gradient(145deg, #1a202c, #2d3748);"></div>
|
||
<span>Forest</span>
|
||
</button>
|
||
<button id="theme-sunset" class="theme-btn" data-theme="sunset">
|
||
<div class="theme-preview" style="background: linear-gradient(145deg, #744210, #c05621);"></div>
|
||
<span>Sunset</span>
|
||
</button>
|
||
<button id="theme-cyberpunk" class="theme-btn" data-theme="cyberpunk">
|
||
<div class="theme-preview" style="background: linear-gradient(145deg, #0a0a0a, #2a0a3a, #1a0520);"></div>
|
||
<span>Cyberpunk</span>
|
||
</button>
|
||
<button id="theme-midnight-rose" class="theme-btn" data-theme="midnight-rose">
|
||
<div class="theme-preview" style="background: linear-gradient(145deg, #1c1820, #3d3046);"></div>
|
||
<span>Midnight Rose</span>
|
||
</button>
|
||
<button id="theme-arctic-ice" class="theme-btn" data-theme="arctic-ice">
|
||
<div class="theme-preview" style="background: linear-gradient(145deg, #f0f8ff, #d1e7ff);"></div>
|
||
<span>Arctic Ice</span>
|
||
</button>
|
||
<button id="theme-cherry-blossom" class="theme-btn" data-theme="cherry-blossom">
|
||
<div class="theme-preview" style="background: linear-gradient(145deg, #fff5f8, #ffd4db);"></div>
|
||
<span>Cherry Blossom</span>
|
||
</button>
|
||
<button id="theme-cosmic-purple" class="theme-btn" data-theme="cosmic-purple">
|
||
<div class="theme-preview" style="background: linear-gradient(145deg, #0f0524, #2d1b69, #4b0082);"></div>
|
||
<span>Cosmic Purple</span>
|
||
</button>
|
||
<button id="theme-emerald-dream" class="theme-btn" data-theme="emerald-dream">
|
||
<div class="theme-preview" style="background: linear-gradient(145deg, #0d2818, #2d5a44);"></div>
|
||
<span>Emerald Dream</span>
|
||
</button>
|
||
<button id="theme-mocha-coffee" class="theme-btn" data-theme="mocha-coffee">
|
||
<div class="theme-preview" style="background: linear-gradient(145deg, #3c2414, #5d3a26);"></div>
|
||
<span>Mocha Coffee</span>
|
||
</button>
|
||
<button id="theme-lavender-fields" class="theme-btn" data-theme="lavender-fields">
|
||
<div class="theme-preview" style="background: linear-gradient(145deg, #f8f4ff, #e6d8ff);"></div>
|
||
<span>Lavender Fields</span>
|
||
</button>
|
||
<button id="theme-custom" class="theme-btn custom-theme-btn" data-theme="custom" style="display: none;">
|
||
<div class="theme-preview" style="background: linear-gradient(145deg, var(--bg), var(--gradient-color));"></div>
|
||
<span>Custom</span>
|
||
</button>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Display Scale -->
|
||
<div class="customization-group">
|
||
<h3>Display Scale</h3>
|
||
<p class="note">Adjust the zoom level for this window. Changes apply immediately.</p>
|
||
<div class="zoom-controls">
|
||
<button class="zoom-btn" id="zoom-decrease" title="Decrease zoom">−</button>
|
||
<span id="display-scale-value" class="zoom-value">100%</span>
|
||
<button class="zoom-btn" id="zoom-increase" title="Increase zoom">+</button>
|
||
</div>
|
||
<div class="zoom-presets">
|
||
<button class="zoom-preset-btn" data-zoom="60">60%</button>
|
||
<button class="zoom-preset-btn" data-zoom="70">70%</button>
|
||
<button class="zoom-preset-btn" data-zoom="80">80%</button>
|
||
<button class="zoom-preset-btn" data-zoom="90">90%</button>
|
||
<button class="zoom-preset-btn" data-zoom="100">100%</button>
|
||
<button class="zoom-preset-btn" data-zoom="110">110%</button>
|
||
<button class="zoom-preset-btn" data-zoom="120">120%</button>
|
||
<button class="zoom-preset-btn" data-zoom="130">130%</button>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Color Customization -->
|
||
<div class="customization-group">
|
||
<h3>Custom Colors</h3>
|
||
<div class="color-controls">
|
||
<div class="color-group">
|
||
<label for="bg-color">Background:</label>
|
||
<input type="color" id="bg-color" value="#121418">
|
||
</div>
|
||
<div class="color-group">
|
||
<label for="gradient-color">Gradient End:</label>
|
||
<input type="color" id="gradient-color" value="#1B1035">
|
||
</div>
|
||
<div class="color-group">
|
||
<label for="accent-color">Accent:</label>
|
||
<input type="color" id="accent-color" value="#7B2EFF">
|
||
</div>
|
||
<div class="color-group">
|
||
<label for="secondary-color">Secondary:</label>
|
||
<input type="color" id="secondary-color" value="#00C6FF">
|
||
</div>
|
||
<div class="color-group">
|
||
<label for="text-color">Text:</label>
|
||
<input type="color" id="text-color" value="#E0E0E0">
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
|
||
|
||
<!-- Logo Customization -->
|
||
<div class="customization-group">
|
||
<h3>Logo & Branding</h3>
|
||
<div class="logo-options">
|
||
<label for="show-logo">
|
||
<input type="checkbox" id="show-logo" checked>
|
||
Show Nebula Logo
|
||
</label>
|
||
<label for="custom-title">
|
||
Custom Title:
|
||
<input type="text" id="custom-title" placeholder="Nebula Browser" maxlength="50">
|
||
</label>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Theme Management -->
|
||
<div class="customization-group">
|
||
<h3>Theme Management</h3>
|
||
<div class="theme-management">
|
||
<button id="save-custom-theme">Save Current as Custom Theme</button>
|
||
<button id="export-theme">Export Theme</button>
|
||
<button id="import-theme">Import Theme</button>
|
||
<input type="file" id="theme-file-input" accept=".json" style="display: none;">
|
||
<button id="reset-to-default">Reset to Default</button>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Live Preview -->
|
||
<div class="customization-group">
|
||
<h3>Preview</h3>
|
||
<div class="preview-container" id="preview-container">
|
||
<div class="preview-home">
|
||
<div class="preview-logo" id="preview-logo">../assets/images/branding/Nebula-Logo.svg</div>
|
||
<div class="preview-text">Nebula</div>
|
||
<div class="preview-search"></div>
|
||
<div class="preview-bookmarks">
|
||
<div class="preview-bookmark"></div>
|
||
<div class="preview-bookmark"></div>
|
||
<div class="preview-bookmark"></div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</section>
|
||
|
||
<!-- History Panel -->
|
||
<section class="tab-panel" id="panel-history" role="tabpanel" aria-labelledby="tab-history">
|
||
<h2>History</h2>
|
||
<div class="customization-group">
|
||
<h3>Search History</h3>
|
||
<ul id="search-history-list"></ul>
|
||
<button id="clear-search-history-btn" style="margin-top: 10px;">Clear Search History</button>
|
||
</div>
|
||
<div class="customization-group">
|
||
<h3>Site History</h3>
|
||
<ul id="site-history-list"></ul>
|
||
<div class="button-row" style="margin-top:10px;">
|
||
<button id="clear-site-history-btn">Clear Site History</button>
|
||
|
||
</div>
|
||
</div>
|
||
</section>
|
||
|
||
<!-- Plugins Panel -->
|
||
<section class="tab-panel" id="panel-plugins" role="tabpanel" aria-labelledby="tab-plugins">
|
||
<h2>Plugins</h2>
|
||
<div class="customization-group">
|
||
<div class="button-row">
|
||
<button id="plugins-reload-all">Reload Plugins</button>
|
||
<span class="note">Changes to renderer preloads may require app restart.</span>
|
||
</div>
|
||
</div>
|
||
<div class="customization-group">
|
||
<h3>Installed</h3>
|
||
<div id="plugins-list" class="plugins-list" role="list"></div>
|
||
</div>
|
||
</section>
|
||
|
||
<!-- About Panel -->
|
||
<section class="tab-panel" id="panel-about" role="tabpanel" aria-labelledby="tab-about">
|
||
<h2>About</h2>
|
||
<div class="customization-group">
|
||
<h3>Application</h3>
|
||
<ul id="about-app">
|
||
<li><strong>Name:</strong> <span id="about-app-name">Loading...</span></li>
|
||
<li><strong>Version:</strong> <span id="about-app-version">Loading...</span></li>
|
||
<li><strong>Packaged:</strong> <span id="about-packaged">Loading...</span></li>
|
||
<li><strong>User data:</strong> <span id="about-userdata" style="word-break: break-all;">Loading...</span></li>
|
||
</ul>
|
||
</div>
|
||
|
||
<div class="customization-group">
|
||
<h3>Runtime</h3>
|
||
<ul id="about-runtime">
|
||
<li><strong>CEF:</strong> <span id="about-cef">Chromium Embedded Framework</span></li>
|
||
<li><strong>Chromium:</strong> <span id="about-chrome">Loading...</span></li>
|
||
<li><strong>Node.js:</strong> <span id="about-node">Loading...</span></li>
|
||
<li><strong>V8:</strong> <span id="about-v8">Loading...</span></li>
|
||
</ul>
|
||
</div>
|
||
|
||
<div class="customization-group">
|
||
<h3>System</h3>
|
||
<ul id="about-system">
|
||
<li><strong>OS:</strong> <span id="about-os">Loading...</span></li>
|
||
<li><strong>CPU:</strong> <span id="about-cpu">Loading...</span></li>
|
||
<li><strong>Architecture:</strong> <span id="about-arch">Loading...</span></li>
|
||
<li><strong>Memory:</strong> <span id="about-mem">Loading...</span></li>
|
||
</ul>
|
||
</div>
|
||
|
||
<div class="customization-group">
|
||
<h3>Runtime Updates</h3>
|
||
<p class="note">Nebula Browser now runs on CEF. Runtime updates are handled by the native application build.</p>
|
||
<p><strong>Nebula Browser:</strong> <span id="about-app-version-copy">Loading...</span></p>
|
||
</div>
|
||
|
||
<div class="customization-group about-actions">
|
||
<button id="copy-about-btn">Copy diagnostics</button>
|
||
<a id="github-link" href="https://github.com/Bobbybear007/NebulaBrowser" class="github-btn" rel="noopener noreferrer">
|
||
<!-- GitHub mark (Octicons) MIT License -->
|
||
<svg viewBox="0 0 16 16" aria-hidden="true" focusable="false" role="img">
|
||
<path d="M8 0C3.58 0 0 3.58 0 8c0 3.54 2.29 6.53 5.47 7.59.4.07.55-.17.55-.38 0-.19-.01-.82-.01-1.49-2.01.37-2.53-.49-2.69-.94-.09-.23-.48-.94-.82-1.13-.28-.15-.68-.52-.01-.53.63-.01 1.08.58 1.23.82.72 1.21 1.87.87 2.33.66.07-.52.28-.87.51-1.07-1.78-.2-3.64-.89-3.64-3.95 0-.87.31-1.59.82-2.15-.08-.2-.36-1.01.08-2.11 0 0 .67-.21 2.2.82.64-.18 1.32-.27 2-.27.68 0 1.36.09 2 .27 1.53-1.04 2.2-.82 2.2-.82.44 1.1.16 1.91.08 2.11.51.56.82 1.27.82 2.15 0 3.07-1.87 3.75-3.65 3.95.29.25.54.73.54 1.48 0 1.07-.01 1.93-.01 2.2 0 .21.15.46.55.38A8.013 8.013 0 0 0 16 8c0-4.42-3.58-8-8-8z"/>
|
||
</svg>
|
||
<span>GitHub</span>
|
||
</a>
|
||
<a id="help-link" href="https://nebula.zambazosmedia.group" class="help-btn" rel="noopener noreferrer">
|
||
<!-- Help icon -->
|
||
<svg viewBox="0 0 24 24" aria-hidden="true" focusable="false" role="img">
|
||
<path d="M12 2a10 10 0 1 0 0 20 10 10 0 0 0 0-20zm0 15a1.25 1.25 0 1 1 0 2.5A1.25 1.25 0 0 1 12 17zm-.02-1.9c-.6 0-1.02-.42-1.02-.98 0-1.97 2.76-1.95 2.76-3.62 0-.77-.66-1.4-1.72-1.4-1 0-1.67.5-2.06 1.22-.3.54-.95.73-1.45.44-.54-.31-.72-1-.42-1.53C7.7 7.7 9.06 6.5 12 6.5c2.26 0 3.98 1.3 3.98 3.35 0 2.74-2.96 2.77-3 3.83-.03.6-.43 1.02-1 1.02z"/>
|
||
</svg>
|
||
<span>Help</span>
|
||
</a>
|
||
</div>
|
||
</section>
|
||
</main>
|
||
</div>
|
||
|
||
<!-- status overlay moved outside of .container -->
|
||
<div id="status" class="status hidden">
|
||
<div class="spinner"></div>
|
||
<span id="status-text"></span>
|
||
</div>
|
||
|
||
<script src="../js/settings.js"></script>
|
||
<script src="../js/customization.js"></script>
|
||
<script>
|
||
// Apply saved theme immediately when page loads
|
||
document.addEventListener('DOMContentLoaded', () => {
|
||
BrowserCustomizer.applyThemeToPage();
|
||
});
|
||
|
||
// Update debug info
|
||
function updateDebugInfo() {
|
||
const debugDiv = document.getElementById('debug-info');
|
||
const localStorage = window.localStorage;
|
||
const hasNativeBridge = !!window.electronAPI;
|
||
const siteHistory = localStorage ? localStorage.getItem('siteHistory') : 'N/A';
|
||
|
||
debugDiv.innerHTML = `
|
||
localStorage available: ${!!localStorage}<br>
|
||
native bridge available: ${hasNativeBridge}<br>
|
||
siteHistory in localStorage: ${siteHistory || 'null'}<br>
|
||
Current domain: ${window.location.hostname}<br>
|
||
Current protocol: ${window.location.protocol}
|
||
`;
|
||
}
|
||
|
||
// Get site history from localStorage in this webview context
|
||
function getSiteHistoryFromLocalStorage() {
|
||
try {
|
||
const history = localStorage.getItem('siteHistory');
|
||
console.log('[SETTINGS DEBUG] localStorage siteHistory:', history);
|
||
return history ? JSON.parse(history) : [];
|
||
} catch (err) {
|
||
console.error('[SETTINGS DEBUG] Error reading from localStorage:', err);
|
||
return [];
|
||
}
|
||
}
|
||
|
||
// Get search history from localStorage in this webview context
|
||
function getSearchHistoryFromLocalStorage() {
|
||
try {
|
||
const history = localStorage.getItem('searchHistory');
|
||
console.log('[SETTINGS DEBUG] localStorage searchHistory:', history);
|
||
return history ? JSON.parse(history) : [];
|
||
} catch (err) {
|
||
console.error('[SETTINGS DEBUG] Error reading search history from localStorage:', err);
|
||
return [];
|
||
}
|
||
}
|
||
|
||
// Sync site history from main browser's localStorage to this webview's localStorage
|
||
function syncSiteHistoryFromMain() {
|
||
try {
|
||
// Try to get the parent window's localStorage
|
||
if (window.parent && window.parent !== window) {
|
||
const parentHistory = window.parent.localStorage.getItem('siteHistory');
|
||
if (parentHistory) {
|
||
localStorage.setItem('siteHistory', parentHistory);
|
||
console.log('[SETTINGS DEBUG] Synced history from parent window');
|
||
return JSON.parse(parentHistory);
|
||
}
|
||
}
|
||
return [];
|
||
} catch (err) {
|
||
console.log('[SETTINGS DEBUG] Could not sync from parent:', err.message);
|
||
return [];
|
||
}
|
||
}
|
||
|
||
// Sync search history from main browser's localStorage to this webview's localStorage
|
||
function syncSearchHistoryFromMain() {
|
||
try {
|
||
// Try to get the parent window's localStorage
|
||
if (window.parent && window.parent !== window) {
|
||
const parentHistory = window.parent.localStorage.getItem('searchHistory');
|
||
if (parentHistory) {
|
||
localStorage.setItem('searchHistory', parentHistory);
|
||
console.log('[SETTINGS DEBUG] Synced search history from parent window');
|
||
return JSON.parse(parentHistory);
|
||
}
|
||
}
|
||
return [];
|
||
} catch (err) {
|
||
console.log('[SETTINGS DEBUG] Could not sync search history from parent:', err.message);
|
||
return [];
|
||
}
|
||
}
|
||
|
||
function addTestHistory() {
|
||
const testSites = [
|
||
'https://www.google.com',
|
||
'https://github.com',
|
||
'https://stackoverflow.com',
|
||
'https://developer.mozilla.org',
|
||
'https://www.wikipedia.org'
|
||
];
|
||
|
||
testSites.forEach(site => {
|
||
try {
|
||
let history = getSiteHistoryFromLocalStorage();
|
||
history = history.filter(item => item !== site);
|
||
history.unshift(site);
|
||
localStorage.setItem('siteHistory', JSON.stringify(history));
|
||
console.log('[SETTINGS DEBUG] Added test site:', site);
|
||
} catch (err) {
|
||
console.error('Error adding test history:', err);
|
||
}
|
||
});
|
||
|
||
loadHistories();
|
||
}
|
||
|
||
async function loadHistories() {
|
||
try {
|
||
console.log('[SETTINGS DEBUG] Loading histories...');
|
||
updateDebugInfo();
|
||
|
||
// First try to sync from parent window
|
||
let siteHistory = syncSiteHistoryFromMain();
|
||
|
||
// If that didn't work, get from local storage
|
||
if (siteHistory.length === 0) {
|
||
siteHistory = getSiteHistoryFromLocalStorage();
|
||
}
|
||
|
||
// Try to get search history from parent or localStorage
|
||
let searchHistory = syncSearchHistoryFromMain();
|
||
if (searchHistory.length === 0) {
|
||
searchHistory = getSearchHistoryFromLocalStorage();
|
||
}
|
||
|
||
const searchList = document.getElementById('search-history-list');
|
||
const siteList = document.getElementById('site-history-list');
|
||
|
||
// Clear existing content
|
||
searchList.innerHTML = '';
|
||
siteList.innerHTML = '';
|
||
|
||
// Populate search history
|
||
if (searchHistory && searchHistory.length > 0) {
|
||
console.log('[SETTINGS DEBUG] Displaying', searchHistory.length, 'search history items');
|
||
searchHistory.forEach(query => {
|
||
const li = document.createElement('li');
|
||
li.style.wordBreak = 'break-all';
|
||
li.textContent = query;
|
||
li.style.color = 'var(--text)';
|
||
searchList.appendChild(li);
|
||
});
|
||
} else {
|
||
const searchLi = document.createElement('li');
|
||
searchLi.textContent = 'No search history yet';
|
||
searchLi.style.fontStyle = 'italic';
|
||
searchLi.style.color = '#666';
|
||
searchList.appendChild(searchLi);
|
||
}
|
||
|
||
// Populate site history
|
||
if (siteHistory && siteHistory.length > 0) {
|
||
console.log('[SETTINGS DEBUG] Displaying', siteHistory.length, 'site history items');
|
||
siteHistory.forEach(item => {
|
||
const li = document.createElement('li');
|
||
li.style.wordBreak = 'break-all';
|
||
// Create a clickable link that asks host to navigate in a new tab
|
||
const a = document.createElement('a');
|
||
a.href = item;
|
||
a.textContent = item;
|
||
a.target = '_blank';
|
||
a.rel = 'noopener noreferrer';
|
||
a.style.color = 'var(--accent)';
|
||
a.style.textDecoration = 'none';
|
||
a.addEventListener('click', (e) => {
|
||
e.preventDefault();
|
||
try {
|
||
if (window.electronAPI && typeof window.electronAPI.sendToHost === 'function') {
|
||
// Ask the host to open this URL in a new tab to keep Settings open
|
||
window.electronAPI.sendToHost('navigate', item, { newTab: true });
|
||
} else if (window.parent && window.parent !== window) {
|
||
// Fallback: postMessage to parent if available
|
||
window.parent.postMessage({ type: 'navigate', url: item }, '*');
|
||
} else {
|
||
// Last resort: open in this webview
|
||
window.location.href = item;
|
||
}
|
||
} catch (err) {
|
||
console.error('[SETTINGS DEBUG] Failed to trigger navigation for', item, err);
|
||
}
|
||
});
|
||
li.appendChild(a);
|
||
siteList.appendChild(li);
|
||
});
|
||
} else {
|
||
console.log('[SETTINGS DEBUG] No site history to display');
|
||
const li = document.createElement('li');
|
||
li.textContent = 'No browsing history found. Browse some websites first!';
|
||
li.style.fontStyle = 'italic';
|
||
li.style.color = '#666';
|
||
siteList.appendChild(li);
|
||
}
|
||
} catch(err) {
|
||
console.error('[SETTINGS DEBUG] Error loading histories:', err);
|
||
|
||
const searchList = document.getElementById('search-history-list');
|
||
const siteList = document.getElementById('site-history-list');
|
||
|
||
const errorLi1 = document.createElement('li');
|
||
errorLi1.textContent = 'Error loading search history: ' + err.message;
|
||
errorLi1.style.color = 'red';
|
||
searchList.appendChild(errorLi1);
|
||
|
||
const errorLi2 = document.createElement('li');
|
||
errorLi2.textContent = 'Error loading site history: ' + err.message;
|
||
errorLi2.style.color = 'red';
|
||
siteList.appendChild(errorLi2);
|
||
}
|
||
}
|
||
|
||
async function clearSiteHistory() {
|
||
try {
|
||
if (window.electronAPI && typeof window.electronAPI.sendToHost === 'function') {
|
||
window.electronAPI.sendToHost('clear-site-history');
|
||
} else if (window.nebulaNative && typeof window.nebulaNative.postMessage === 'function') {
|
||
window.nebulaNative.postMessage('clear-site-history');
|
||
}
|
||
|
||
// Clear from localStorage
|
||
localStorage.removeItem('siteHistory');
|
||
console.log('[SETTINGS DEBUG] Cleared site history from localStorage');
|
||
|
||
loadHistories(); // Refresh the display
|
||
} catch (err) {
|
||
console.error('Error clearing site history:', err);
|
||
}
|
||
}
|
||
|
||
async function clearSearchHistory() {
|
||
try {
|
||
// Clear from localStorage
|
||
localStorage.removeItem('searchHistory');
|
||
console.log('[SETTINGS DEBUG] Cleared search history from localStorage');
|
||
|
||
// Also clear in parent window if accessible
|
||
if (window.parent && window.parent !== window) {
|
||
try {
|
||
window.parent.localStorage.removeItem('searchHistory');
|
||
console.log('[SETTINGS DEBUG] Cleared search history from parent');
|
||
} catch (e) {
|
||
console.log('[SETTINGS DEBUG] Could not clear parent search history:', e.message);
|
||
}
|
||
}
|
||
|
||
loadHistories(); // Refresh the display
|
||
} catch (err) {
|
||
console.error('Error clearing search history:', err);
|
||
}
|
||
}
|
||
|
||
// Load histories on page load
|
||
window.addEventListener('DOMContentLoaded', () => {
|
||
console.log('[SETTINGS DEBUG] DOM loaded, window.electronAPI:', !!window.electronAPI);
|
||
loadHistories();
|
||
|
||
// Refresh history every few seconds to pick up new browsing
|
||
setInterval(loadHistories, 3000);
|
||
|
||
// Add test history button functionality
|
||
const addTestBtn = document.getElementById('add-test-history-btn');
|
||
if (addTestBtn) {
|
||
addTestBtn.addEventListener('click', addTestHistory);
|
||
}
|
||
|
||
// Add clear buttons functionality
|
||
const clearSiteBtn = document.getElementById('clear-site-history-btn');
|
||
const clearSearchBtn = document.getElementById('clear-search-history-btn');
|
||
|
||
if (clearSiteBtn) {
|
||
clearSiteBtn.addEventListener('click', clearSiteHistory);
|
||
}
|
||
if (clearSearchBtn) {
|
||
clearSearchBtn.addEventListener('click', clearSearchHistory);
|
||
}
|
||
});
|
||
</script>
|
||
</body>
|
||
</html>
|