Add advanced reload and history clearing features
Introduces hard reload and fresh reload buttons to the UI, allowing users to reload pages while ignoring cache or with a cache-busting parameter. Refactors session and browser data clearing logic to handle multiple sessions and resets history JSON files. Adds per-section clear buttons for site and search history in settings, improving user control over stored data.
This commit is contained in:
@@ -149,44 +149,39 @@ app.whenReady().then(async () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
// Optimize session settings for performance and OAuth compatibility
|
// Optimize session settings for performance and OAuth compatibility
|
||||||
const ses = session.defaultSession;
|
const sessionsToConfigure = [session.fromPartition('persist:main'), session.defaultSession];
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// Configure session for OAuth compatibility (Google, etc.)
|
for (const ses of sessionsToConfigure) {
|
||||||
ses.setPermissionRequestHandler((webContents, permission, callback) => {
|
// Configure session for OAuth compatibility (Google, etc.)
|
||||||
// Allow necessary permissions for OAuth flows
|
ses.setPermissionRequestHandler((webContents, permission, callback) => {
|
||||||
if (['notifications', 'geolocation', 'camera', 'microphone'].includes(permission)) {
|
// Allow necessary permissions for OAuth flows
|
||||||
callback(false); // Deny by default for privacy
|
if (['notifications', 'geolocation', 'camera', 'microphone'].includes(permission)) {
|
||||||
} else {
|
callback(false); // Deny by default for privacy
|
||||||
callback(true); // Allow others like storage access
|
} else {
|
||||||
}
|
callback(true); // Allow others like storage access
|
||||||
});
|
}
|
||||||
|
});
|
||||||
|
|
||||||
// Configure user agent for better compatibility
|
// Configure user agent for better compatibility
|
||||||
ses.setUserAgent('Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36 Nebula/1.0.0');
|
ses.setUserAgent('Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36 Nebula/1.0.0');
|
||||||
|
|
||||||
// Configure cookies for OAuth compatibility
|
// Configure cookies for OAuth compatibility
|
||||||
ses.cookies.on('changed', (event, cookie, cause, removed) => {
|
ses.cookies.on('changed', (event, cookie, cause, removed) => {
|
||||||
// Log cookie changes for debugging OAuth issues
|
// Log cookie changes for debugging OAuth issues
|
||||||
if (cookie.domain.includes('google') || cookie.domain.includes('accounts')) {
|
if (cookie.domain && (cookie.domain.includes('google') || cookie.domain.includes('accounts'))) {
|
||||||
console.log(`Cookie ${removed ? 'removed' : 'added'}: ${cookie.name} for ${cookie.domain}`);
|
console.log(`Cookie ${removed ? 'removed' : 'added'}: ${cookie.name} for ${cookie.domain}`);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// Enable request/response caching
|
// Optional: add headers only for OAuth flows; avoid forcing cache headers globally
|
||||||
ses.webRequest.onBeforeSendHeaders((details, callback) => {
|
ses.webRequest.onBeforeSendHeaders((details, callback) => {
|
||||||
// Add headers for better OAuth compatibility
|
if (details.url.includes('accounts.google.com') || details.url.includes('oauth')) {
|
||||||
details.requestHeaders['Cache-Control'] = 'max-age=3600';
|
details.requestHeaders['Referrer-Policy'] = 'strict-origin-when-cross-origin';
|
||||||
// Ensure we accept third-party cookies for OAuth flows
|
details.requestHeaders['Accept'] = 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8';
|
||||||
details.requestHeaders['Accept'] = 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8';
|
}
|
||||||
// Add referrer policy for OAuth compatibility
|
callback({ requestHeaders: details.requestHeaders });
|
||||||
if (details.url.includes('accounts.google.com') || details.url.includes('oauth')) {
|
});
|
||||||
details.requestHeaders['Referrer-Policy'] = 'strict-origin-when-cross-origin';
|
}
|
||||||
}
|
|
||||||
callback({ requestHeaders: details.requestHeaders });
|
|
||||||
});
|
|
||||||
|
|
||||||
// Skip preload registration as it's handled in window options
|
|
||||||
console.log('Session configured successfully for OAuth compatibility');
|
console.log('Session configured successfully for OAuth compatibility');
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error('Session setup error:', err);
|
console.error('Session setup error:', err);
|
||||||
@@ -330,26 +325,35 @@ ipcMain.handle('save-bookmarks', async (event, bookmarks) => {
|
|||||||
|
|
||||||
ipcMain.handle('clear-browser-data', async () => {
|
ipcMain.handle('clear-browser-data', async () => {
|
||||||
try {
|
try {
|
||||||
const ses = session.defaultSession;
|
const sessionsToClear = [session.defaultSession, session.fromPartition('persist:main')];
|
||||||
|
|
||||||
// Clear cookies
|
for (const ses of sessionsToClear) {
|
||||||
await ses.clearStorageData({ storages: ['cookies'] });
|
if (!ses) continue;
|
||||||
|
// Clear all common site storage types
|
||||||
// Clear local storage and other storage data
|
await ses.clearStorageData({
|
||||||
await ses.clearStorageData({ storages: ['localstorage', 'indexdb', 'filesystem', 'websql'] });
|
storages: [
|
||||||
|
'cookies',
|
||||||
// Clear cache
|
'localstorage',
|
||||||
await ses.clearCache();
|
'indexdb',
|
||||||
|
'filesystem',
|
||||||
// Clear HTTP authentication cache
|
'websql',
|
||||||
await ses.clearAuthCache();
|
'serviceworkers',
|
||||||
|
'caches',
|
||||||
// Clear all cookies explicitly to ensure logged-in accounts are logged out
|
'shadercache',
|
||||||
const cookies = await ses.cookies.get({});
|
'appcache'
|
||||||
for (const cookie of cookies) {
|
],
|
||||||
await ses.cookies.remove(cookie.url, cookie.name);
|
});
|
||||||
|
// Clear caches and auth
|
||||||
|
await ses.clearCache();
|
||||||
|
await ses.clearAuthCache();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Also reset on-disk history JSON files managed by the app
|
||||||
|
const siteHistoryPath = path.join(__dirname, 'site-history.json');
|
||||||
|
const searchHistoryPath = path.join(__dirname, 'search-history.json');
|
||||||
|
try { await fs.promises.writeFile(siteHistoryPath, JSON.stringify([], null, 2)); } catch {}
|
||||||
|
try { await fs.promises.writeFile(searchHistoryPath, JSON.stringify([], null, 2)); } catch {}
|
||||||
|
|
||||||
return true; // Indicate success
|
return true; // Indicate success
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Failed to clear browser data:', error);
|
console.error('Failed to clear browser data:', error);
|
||||||
@@ -357,6 +361,17 @@ ipcMain.handle('clear-browser-data', async () => {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Optional: standalone clear for search history JSON
|
||||||
|
ipcMain.handle('clear-search-history', async () => {
|
||||||
|
const filePath = path.join(__dirname, 'search-history.json');
|
||||||
|
try {
|
||||||
|
await fs.promises.writeFile(filePath, JSON.stringify([], null, 2));
|
||||||
|
return true;
|
||||||
|
} catch (err) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
ipcMain.handle('get-zoom-factor', event => {
|
ipcMain.handle('get-zoom-factor', event => {
|
||||||
const wc = BrowserWindow.fromWebContents(event.sender).webContents;
|
const wc = BrowserWindow.fromWebContents(event.sender).webContents;
|
||||||
return wc.getZoomFactor();
|
return wc.getZoomFactor();
|
||||||
|
|||||||
@@ -51,6 +51,8 @@
|
|||||||
<span id="zoom-percent">100%</span>
|
<span id="zoom-percent">100%</span>
|
||||||
<button id="zoom-in-btn">+</button>
|
<button id="zoom-in-btn">+</button>
|
||||||
</div>
|
</div>
|
||||||
|
<button id="hard-reload-btn">Hard Reload (Ignore Cache)</button>
|
||||||
|
<button id="fresh-reload-btn">Reload Fresh (Add Cache-Buster)</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -674,6 +674,30 @@ function reload() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function hardReload() {
|
||||||
|
const webview = document.getElementById(`tab-${activeTabId}`);
|
||||||
|
if (webview && typeof webview.reloadIgnoringCache === 'function') {
|
||||||
|
webview.reloadIgnoringCache();
|
||||||
|
scheduleUpdateNavButtons();
|
||||||
|
} else if (webview) {
|
||||||
|
// Fallback
|
||||||
|
webview.reload();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function freshReload() {
|
||||||
|
const webview = document.getElementById(`tab-${activeTabId}`);
|
||||||
|
if (!webview) return;
|
||||||
|
try {
|
||||||
|
const u = new URL(webview.getURL());
|
||||||
|
u.searchParams.set('_bust', Date.now().toString());
|
||||||
|
webview.src = u.toString();
|
||||||
|
} catch {
|
||||||
|
// If URL parsing fails (e.g., internal pages), fall back to hard reload
|
||||||
|
hardReload();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Function to open the Settings page
|
// Function to open the Settings page
|
||||||
function openSettings() {
|
function openSettings() {
|
||||||
createTab('browser://settings');
|
createTab('browser://settings');
|
||||||
@@ -776,6 +800,10 @@ window.addEventListener('DOMContentLoaded', () => {
|
|||||||
// only now bind the reload button (guaranteed to exist)
|
// only now bind the reload button (guaranteed to exist)
|
||||||
const reloadBtn = document.getElementById('reload-btn');
|
const reloadBtn = document.getElementById('reload-btn');
|
||||||
reloadBtn.addEventListener('click', reload);
|
reloadBtn.addEventListener('click', reload);
|
||||||
|
const hardReloadBtn = document.getElementById('hard-reload-btn');
|
||||||
|
if (hardReloadBtn) hardReloadBtn.addEventListener('click', hardReload);
|
||||||
|
const freshReloadBtn = document.getElementById('fresh-reload-btn');
|
||||||
|
if (freshReloadBtn) freshReloadBtn.addEventListener('click', freshReload);
|
||||||
|
|
||||||
// bind zoom buttons (single binding)
|
// bind zoom buttons (single binding)
|
||||||
const zoomInBtn = document.getElementById('zoom-in-btn');
|
const zoomInBtn = document.getElementById('zoom-in-btn');
|
||||||
|
|||||||
+42
-14
@@ -1,13 +1,7 @@
|
|||||||
// Try to get ipcRenderer, but don't fail if it's not available
|
// Prefer contextBridge-exposed API
|
||||||
let ipcRenderer = null;
|
const ipc = (window.electronAPI && typeof window.electronAPI.invoke === 'function')
|
||||||
try {
|
? window.electronAPI
|
||||||
if (typeof require !== 'undefined') {
|
: null;
|
||||||
const electron = require('electron');
|
|
||||||
ipcRenderer = electron.ipcRenderer;
|
|
||||||
}
|
|
||||||
} catch (e) {
|
|
||||||
console.log('[SETTINGS] Electron IPC not available, some features may be limited');
|
|
||||||
}
|
|
||||||
|
|
||||||
let clearBtn = document.getElementById('clear-data-btn');
|
let clearBtn = document.getElementById('clear-data-btn');
|
||||||
const statusDiv = document.getElementById('status');
|
const statusDiv = document.getElementById('status');
|
||||||
@@ -39,14 +33,18 @@ function attachClearHandler(btn) {
|
|||||||
btn.onclick = async () => {
|
btn.onclick = async () => {
|
||||||
if (statusDiv && statusText) {
|
if (statusDiv && statusText) {
|
||||||
statusDiv.classList.remove('hidden');
|
statusDiv.classList.remove('hidden');
|
||||||
statusText.textContent = 'Clearing all browser data...';
|
statusText.textContent = 'Clearing cookies, storage, cache, and history...';
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
if (ipcRenderer) {
|
if (ipc) {
|
||||||
const ok = await ipcRenderer.invoke('clear-browser-data');
|
const ok = await ipc.invoke('clear-browser-data');
|
||||||
|
// Also clear localStorage site history in this context
|
||||||
|
try { localStorage.removeItem('siteHistory'); } catch {}
|
||||||
|
// Try to refresh lists if present
|
||||||
|
try { if (typeof loadHistories === 'function') await loadHistories(); } catch {}
|
||||||
showStatus(ok
|
showStatus(ok
|
||||||
? 'All browser data and bookmarks cleared!'
|
? 'All browser data cleared.'
|
||||||
: 'Failed to clear browser data.');
|
: 'Failed to clear browser data.');
|
||||||
} else {
|
} else {
|
||||||
showStatus('Clear data feature not available in this context.');
|
showStatus('Clear data feature not available in this context.');
|
||||||
@@ -70,6 +68,36 @@ window.addEventListener('DOMContentLoaded', () => {
|
|||||||
clearBtn = document.getElementById('clear-data-btn');
|
clearBtn = document.getElementById('clear-data-btn');
|
||||||
attachClearHandler(clearBtn);
|
attachClearHandler(clearBtn);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Wire per-section clear buttons to main when possible
|
||||||
|
const clearSiteBtn = document.getElementById('clear-site-history-btn');
|
||||||
|
if (clearSiteBtn) {
|
||||||
|
clearSiteBtn.addEventListener('click', async () => {
|
||||||
|
try {
|
||||||
|
// Clear localStorage copy
|
||||||
|
try { localStorage.removeItem('siteHistory'); } catch {}
|
||||||
|
// Ask main to clear file-based history for consistency
|
||||||
|
if (ipc) { await ipc.invoke('clear-site-history'); }
|
||||||
|
showStatus('Site history cleared');
|
||||||
|
try { if (typeof loadHistories === 'function') await loadHistories(); } catch {}
|
||||||
|
} catch (e) {
|
||||||
|
console.error('Clear site history error:', e);
|
||||||
|
showStatus('Failed clearing site history');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
const clearSearchBtn = document.getElementById('clear-search-history-btn');
|
||||||
|
if (clearSearchBtn) {
|
||||||
|
clearSearchBtn.addEventListener('click', async () => {
|
||||||
|
try {
|
||||||
|
if (ipc) { await ipc.invoke('clear-search-history'); }
|
||||||
|
showStatus('Search history cleared');
|
||||||
|
} catch (e) {
|
||||||
|
console.error('Clear search history error:', e);
|
||||||
|
showStatus('Failed clearing search history');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// Tabs: simple controller
|
// Tabs: simple controller
|
||||||
|
|||||||
+1
-3
@@ -1,3 +1 @@
|
|||||||
[
|
[]
|
||||||
|
|
||||||
]
|
|
||||||
Reference in New Issue
Block a user