Page back/forward: Alt+Left/Right, mouse side buttons, optional on-screen buttons
Alt+Left/Right now go back/forward within the page (the standard browser keys) instead of switching sites; sites switch with Ctrl+Tab, Ctrl+[ ] and the standard Ctrl+PageUp/PageDown. New enableHistoryButtons option (off by default) shows half-transparent back/forward buttons at the top middle. Settable from the terminal menu and the Web UI. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_013wi3ZQveYdjfcrEsyazq32
This commit is contained in:
+41
-2
@@ -60,6 +60,7 @@ let allowNavigation='same-origin';
|
||||
let enablePauseButton=true;
|
||||
let enableKeyboardButton=true;
|
||||
let enableNavButton=true;
|
||||
let enableHistoryButtons=false;
|
||||
let enablePasswordProtection=false;
|
||||
let lockoutPassword="";
|
||||
let lockoutTimeout=0;
|
||||
@@ -102,6 +103,7 @@ function loadConfig(){
|
||||
enablePauseButton=(config.enablePauseButton!==false);
|
||||
enableKeyboardButton=(config.enableKeyboardButton!==false);
|
||||
enableNavButton=(config.enableNavButton!==false);
|
||||
enableHistoryButtons=(config.enableHistoryButtons===true);
|
||||
enablePasswordProtection=(config.enablePasswordProtection===true);
|
||||
lockoutPassword=config.lockoutPassword||"";
|
||||
lockoutTimeout=(config.lockoutTimeout||0)*60000; // Convert minutes to ms
|
||||
@@ -122,6 +124,7 @@ function loadConfig(){
|
||||
console.log('[CONFIG] Navigation:',allowNavigation);
|
||||
console.log('[CONFIG] Pause button:',enablePauseButton);
|
||||
console.log('[CONFIG] Keyboard button:',enableKeyboardButton);
|
||||
console.log('[CONFIG] Back/forward buttons:',enableHistoryButtons);
|
||||
console.log('[CONFIG] Password protection:',enablePasswordProtection);
|
||||
console.log('[CONFIG] Lockout timeout:',lockoutTimeout/60000,'minutes');
|
||||
if(lockoutAtTime)console.log('[CONFIG] Lock at time:',lockoutAtTime);
|
||||
@@ -1145,6 +1148,27 @@ function returnToTabs(){
|
||||
markActivity();
|
||||
}
|
||||
|
||||
// Page back/forward in the site that's on screen (Alt+Left / Alt+Right, the
|
||||
// mouse's side buttons, and the optional on-screen buttons). Not while the
|
||||
// screen is locked or a dialog (PIN, WiFi, power...) is open on top - the
|
||||
// keys would silently navigate the page hidden behind it.
|
||||
function historyGo(direction){
|
||||
if(isLockedOut)return;
|
||||
for(const w of [pinWindow,wifiWindow,promptWindow,pauseWindow]){
|
||||
if(w&&!w.isDestroyed())return;
|
||||
}
|
||||
const view=showingHidden?hiddenViews[currentHiddenIndex]:views[currentIndex];
|
||||
if(!view||!view.webContents||view.webContents.isDestroyed())return;
|
||||
const wc=view.webContents;
|
||||
const nav=wc.navigationHistory;
|
||||
if(direction==='back'){
|
||||
if(nav?nav.canGoBack():wc.canGoBack()){nav?nav.goBack():wc.goBack();}
|
||||
}else{
|
||||
if(nav?nav.canGoForward():wc.canGoForward()){nav?nav.goForward():wc.goForward();}
|
||||
}
|
||||
markActivity();
|
||||
}
|
||||
|
||||
function showPinEntry(){
|
||||
if(pinWindow&&!pinWindow.isDestroyed()){
|
||||
pinWindow.focus();
|
||||
@@ -1526,6 +1550,11 @@ async function createWindow(){
|
||||
|
||||
mainWindow.on('focus',()=>markActivity());
|
||||
mainWindow.webContents.on('before-input-event',()=>markActivity());
|
||||
// Mouse side buttons (back/forward). Reported by the window on Linux.
|
||||
mainWindow.on('app-command',(event,command)=>{
|
||||
if(command==='browser-backward')historyGo('back');
|
||||
else if(command==='browser-forward')historyGo('forward');
|
||||
});
|
||||
|
||||
if(!tabs.length){
|
||||
mainWindow.loadURL('data:text/html,<body>No Sites Configured</body>');
|
||||
@@ -1611,6 +1640,7 @@ async function createWindow(){
|
||||
console.log('[MAIN] Page loaded - sending keyboard-button-enabled: '+enableKeyboardButton);
|
||||
|
||||
view.webContents.send('nav-button-enabled',enableNavButton);
|
||||
view.webContents.send('history-buttons-enabled',enableHistoryButtons);
|
||||
console.log('[MAIN] Page loaded - sending nav-button-enabled: '+enableNavButton);
|
||||
|
||||
console.log('[MAIN] Page loaded - resending pause-button-visibility: '+shouldShow+' for '+t.url);
|
||||
@@ -1654,6 +1684,9 @@ async function createWindow(){
|
||||
else if(action==='reload'){app.relaunch();app.quit();}
|
||||
});
|
||||
ipcMain.on('toggle-hidden',toggleHidden);
|
||||
ipcMain.on('history-nav',(event,direction)=>{
|
||||
if(direction==='back'||direction==='forward')historyGo(direction);
|
||||
});
|
||||
ipcMain.on('return-to-tabs',forceReturnToTabs);
|
||||
ipcMain.on('user-activity',markActivity);
|
||||
ipcMain.on('show-keyboard',()=>{showHTMLKeyboard();});
|
||||
@@ -1843,9 +1876,15 @@ async function createWindow(){
|
||||
globalShortcut.register('Control+Shift+Tab',()=>{prevTab();});
|
||||
globalShortcut.register('Control+]',()=>{nextTab();});
|
||||
globalShortcut.register('Control+[',()=>{prevTab();});
|
||||
globalShortcut.register('Alt+Right',()=>{nextTab();});
|
||||
globalShortcut.register('Alt+Left',()=>{prevTab();});
|
||||
// The standard browser keys for switching tabs. (Alt+Left/Right used to
|
||||
// switch sites; they are now page back/forward, below.)
|
||||
globalShortcut.register('Control+PageDown',()=>{nextTab();});
|
||||
globalShortcut.register('Control+PageUp',()=>{prevTab();});
|
||||
}
|
||||
|
||||
// Standard browser keys for page back/forward.
|
||||
globalShortcut.register('Alt+Left',()=>{historyGo('back');});
|
||||
globalShortcut.register('Alt+Right',()=>{historyGo('forward');});
|
||||
|
||||
globalShortcut.register('F10',toggleHidden);
|
||||
globalShortcut.register('Control+H',toggleHidden);
|
||||
|
||||
@@ -115,6 +115,19 @@ ipcRenderer.on('keyboard-button-enabled',(event,enabled)=>{
|
||||
}
|
||||
});
|
||||
|
||||
// On-screen back/forward buttons (top middle, half transparent) - an
|
||||
// option for screens with no keyboard or mouse side buttons.
|
||||
let historyButtonsEnabled=false;
|
||||
let historyBar=null;
|
||||
let historyBarHideTimer=null;
|
||||
ipcRenderer.on('history-buttons-enabled',(event,enabled)=>{
|
||||
historyButtonsEnabled=enabled===true;
|
||||
console.log('[HISTORY-BTN] Back/forward buttons enabled: '+historyButtonsEnabled);
|
||||
if(historyBar&&!historyButtonsEnabled){
|
||||
historyBar.style.display='none';
|
||||
}
|
||||
});
|
||||
|
||||
ipcRenderer.on('nav-button-enabled',(event,enabled)=>{
|
||||
navButtonEnabled=enabled;
|
||||
console.log('[NAV-BTN] Navigation button enabled: '+enabled);
|
||||
@@ -253,6 +266,56 @@ window.addEventListener('DOMContentLoaded',()=>{
|
||||
document.body.appendChild(navButton);
|
||||
}
|
||||
|
||||
// Back/forward buttons, top middle. The corners are often all taken by the
|
||||
// menu, pause, keyboard and power buttons, so these sit between them.
|
||||
const HISTORY_BAR_HIDE_DELAY=5000;
|
||||
function createHistoryBar(){
|
||||
if(historyBar)return;
|
||||
historyBar=document.createElement('div');
|
||||
historyBar.id='electron-history-bar';
|
||||
historyBar.style.cssText=`
|
||||
position:fixed;top:12px;left:50%;transform:translateX(-50%);
|
||||
display:none;gap:14px;z-index:999999;opacity:0.5;
|
||||
transition:opacity 0.15s;user-select:none;
|
||||
`;
|
||||
const makeButton=(label,direction,path)=>{
|
||||
const b=document.createElement('div');
|
||||
b.title=label;
|
||||
b.innerHTML='<svg width="30" height="30" viewBox="0 0 24 24" fill="white"><path d="'+path+'"/></svg>';
|
||||
b.style.cssText=`
|
||||
width:56px;height:56px;background:rgba(44,62,80,0.9);
|
||||
border:2px solid rgba(255,255,255,0.9);border-radius:50%;
|
||||
display:flex;align-items:center;justify-content:center;cursor:pointer;
|
||||
`;
|
||||
b.addEventListener('click',(e)=>{
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
ipcRenderer.send('history-nav',direction);
|
||||
showHistoryBar();
|
||||
});
|
||||
return b;
|
||||
};
|
||||
historyBar.append(
|
||||
makeButton('Back','back','M15.41 7.41L14 6l-6 6 6 6 1.41-1.41L10.83 12z'),
|
||||
makeButton('Forward','forward','M8.59 16.59L10 18l6-6-6-6-1.41 1.41L13.17 12z')
|
||||
);
|
||||
historyBar.addEventListener('mouseenter',()=>{historyBar.style.opacity='0.9';});
|
||||
historyBar.addEventListener('mouseleave',()=>{historyBar.style.opacity='0.5';});
|
||||
document.body.appendChild(historyBar);
|
||||
}
|
||||
|
||||
function showHistoryBar(){
|
||||
if(!historyButtonsEnabled)return;
|
||||
if(!historyBar)createHistoryBar();
|
||||
if(!historyBar)return;
|
||||
historyBar.style.display='flex';
|
||||
if(historyBarHideTimer)clearTimeout(historyBarHideTimer);
|
||||
historyBarHideTimer=setTimeout(()=>{
|
||||
if(historyBar)historyBar.style.display='none';
|
||||
historyBarHideTimer=null;
|
||||
},HISTORY_BAR_HIDE_DELAY);
|
||||
}
|
||||
|
||||
// Power button in top-right corner (follows same show/hide logic as nav button)
|
||||
let powerButton=null;
|
||||
let powerButtonHideTimer=null;
|
||||
@@ -918,11 +981,23 @@ window.addEventListener('DOMContentLoaded',()=>{
|
||||
if(navButtonEnabled){
|
||||
showNavButton();
|
||||
}
|
||||
showHistoryBar();
|
||||
|
||||
// Always show power button on user interaction
|
||||
showPowerButton();
|
||||
}
|
||||
|
||||
// Back/forward buttons also appear on plain mouse movement, for screens
|
||||
// with a mouse but no touch (the other buttons wait for a click/keypress).
|
||||
let lastHistoryMove=0;
|
||||
document.addEventListener('mousemove',()=>{
|
||||
if(!historyButtonsEnabled)return;
|
||||
const now=Date.now();
|
||||
if(now-lastHistoryMove<300)return;
|
||||
lastHistoryMove=now;
|
||||
showHistoryBar();
|
||||
},{passive:true,capture:true});
|
||||
|
||||
// Show pause button on any user interaction
|
||||
const pauseButtonTriggers=['mousedown','touchstart','keydown'];
|
||||
pauseButtonTriggers.forEach(eventType=>{
|
||||
|
||||
Reference in New Issue
Block a user