Autoscroll Active Tab into view in Vertical Tabbar on mouseover
-
So, I have made a request last year in https://forum.vivaldi.net/post/202414, but it seem Vivaldi dev aren't interested in this idea, probably because most user are using the default tab on top position. So yesterday, I decide to DIY with CSS mod... And my final conclusion after many, many failures is it can't be done with CSS alone (or I'm just too dumb to made one that works)...
So, I would like to request from Javascript gurus to take a shot at this problem. I don't need anything fancy (like in my previous request), I just want the active tab to be autoscroll into visible position (1 time) when I mouseover the tabbar. This will help me save a lot of time when accessing the automate tabbar if the active tab is out of view.
Is that possible? Or it also can't be done with JS, & only V dev can implement it?
Thanks for your time, efforts, & support. -
Try this
(function () { function doMod() { let isModEnabled = false; function scrollToTab(tabInfo) { if (isModEnabled) { let tab = document.querySelector('#tab-' + tabInfo.tabId); tab.scrollIntoViewIfNeeded(); } } function checkIsModEnabled() { vivaldi.prefs.get('vivaldi.tabs.visible', function(tabsVisible){ if (tabsVisible) vivaldi.prefs.get('vivaldi.tabs.bar.position', function(barPosition){ if (barPosition === 'left' || barPosition === 'right' || barPosition === 1 || barPosition === 2) isModEnabled = true; else isModEnabled = false; }); else isModEnabled = false; }); } checkIsModEnabled(); vivaldi.prefs.onChanged.addListener(function(pref){ if (pref.path === 'vivaldi.tabs.visible' || pref.path === 'vivaldi.tabs.bar.position') checkIsModEnabled(); }); chrome.tabs.onActivated.addListener(scrollToTab); } setTimeout(function wait() { let activeTab = document.querySelector('#tabs-container .tab-strip .tab.active'); if (activeTab) doMod(); else setTimeout(wait, 300); }, 300); })();
Edited
-
@potmeklecbohdan YES! Thanks for your help!
-
@dude99 Ah, sorry, there is an unused constant (I edited the post)
-
@potmeklecbohdan Got it. So, the autoscroll is activated by switching tab, correct?
Thanks again.
-
@dude99 Yes. In fact I re-read the title when I wanted to remove the constant, but was too lazy to re-code it and I don't know if you'd really like that behavior (it looks unusable to me)
-
@potmeklecbohdan I think it's fine. I can simply press 2 & then 1 to find the active tab. It's still much faster than scroll down/up to look for it.
-
@dude99 This should scroll also when you leave the tab bar (but I didn't test it)
(function () { function doMod() { let isModEnabled = false; const tabBar = document.querySelector('#tabs-container'); function scrollToTab(tabInfo) { if (isModEnabled) { let tab; if (tabInfo && tabInfo.tabId) tab = document.querySelector('#tab-' + tabInfo.tabId); else tab = document.querySelector('#tabs-container .tab-strip .tab.active'); if (tab) tab.scrollIntoViewIfNeeded(); } } function checkIsModEnabled() { vivaldi.prefs.get('vivaldi.tabs.visible', function(tabsVisible){ if (tabsVisible) vivaldi.prefs.get('vivaldi.tabs.bar.position', function(barPosition){ if (barPosition === 'left' || barPosition === 'right' || barPosition === 1 || barPosition === 2) isModEnabled = true; else isModEnabled = false; }); else isModEnabled = false; }); } checkIsModEnabled(); vivaldi.prefs.onChanged.addListener(function(pref){ if (pref.path === 'vivaldi.tabs.visible' || pref.path === 'vivaldi.tabs.bar.position') checkIsModEnabled(); }); chrome.tabs.onActivated.addListener(scrollToTab); tabBar.addEventListener('mouseleave', scrollToTab); } setTimeout(function wait() { let activeTab = document.querySelector('#tabs-container .tab-strip .tab.active'); if (activeTab) doMod(); else setTimeout(wait, 300); }, 300); })();
-
@potmeklecbohdan Wow, you r on fire!
Yes, it's working great. Thanks. -
Here is a slight change to the 2nd mod from above by potmeklecbohdan...
For those who preferred on demand activation only, instead of automatic activation when mouse away from tabbar -- simply replace
tabBar.addEventListener('mouseleave', scrollToTab);
with this 2 lines:trashButton = document.querySelector('#tabs-container > div.sync-and-trash-container'); trashButton.addEventListener('click', scrollToTab);
With this change you can now click on the empty area around trashcan (or trashcan button) to scroll active tab into view. You can also replace
'click'
with'dblclick'
for double-click activation instead.Again, all thanks to potmeklecbohdan for this handy mod!
And I hope Vivaldi team will read this thread & implant this feature into future Vivaldi! -
@dude99 To make it even better:
document.querySelector('#tabs-container > div.sync-and-trash-container').addEventListener('click', scrollToTab);
and replace
setTimeout(function wait() { let activeTab = document.querySelector('#tabs-container .tab-strip .tab.active'); if (activeTab)
with
setTimeout(function wait() { let activeTab = document.querySelector('#tabs-container .tab-strip .tab.active'); let trashButton = document.querySelector('#tabs-container > div.sync-and-trash-container'); if (activeTab && trashButton)
-
@potmeklecbohdan Oh, I don't know much about JavaScript; I just learn from your code & change it. LOL
Thanks for the improvement.
-
@potmeklecbohdan this is a useful script but for my version (2.11.1811.41) I could skip the timer part and it still worked. Did you experience any race conditions when you created this and you had to add the timer?
PS: this script is not fool-proof: if you watch a video full screen, once you exit FS mode, Vivaldi scrolls to the top. Obviously this cannot be caught by the script without further tweaking.
-
@adamstyl Unfortunately this is cause by Vivaldi's default FS behavior, as it disabled the tabbar during FS mode. Thus when you exit FS it will reload the tabbar & thus it end up on top position.
I hate this behavior too, that's why I rarely use FS mode. Maybe you can add a feature request to change this behavior.
-
@dude99 You should have told me earlier! Now I'm not sure if I'll fix it (as I got even lazier than I used to be), but I don't think it's difficult.
-
@potmeklecbohdan I learn about it by studying the common.css a while back, my guess is you can do it by overwrite FS mode css so that FS mode doesn't affect the tabbar. It's a very messy method, I give up half way because it involved too many changes...
-
@potmeklecbohdan said:
but I don't think it's difficult.
Whoops! I realised it would be easier to write from scratch, as I got lost in recursive calls and callbacksβ¦
Wait, wait⦠you say that it works after FS and de-FS, but the first time the tab bar is shown it is scrolled to top? Because if yes, there could be a simpler solution (just one more event listener).
-
@potmeklecbohdan Ok. I noticed 2 things:
-
All js mod seems to stop working after enter
& exitFS. I have to close & reopen the window to restore their functions, is this a "bug" or "feature"??? -
The common.css have changed since the last time I studied it, in line 6090 you will find the CSS FS mode for tabbar, it seems to simplified & should be easy to fix this time around.
EDIT:
This css mod will overwrite FS's tabbar (on left) & restore it's basic functionalities in FS:#browser.fullscreen #tabs-container { display: flex; position: fixed; top: 0; bottom: 0; left:0; z-index: 9; flex-direction: column; background: var(--colorBg); } #browser.fullscreen #tabs-container.overflow .tab-strip { overflow-x: hidden; overflow-y: auto; }
But unfortunately the result is very disappointing, because the first problem I talk about seems to begin when entering FS, not after exiting FS . All js mod seems to stop working during FS mode & never restore even exited FS.
So, that's all I can do for now, good luck on trying to fix this with js mod!
-
-
@dude99 The above post CSS mod is just for proof of concept, it's not really practical for FS browsing... For those interested in actually usable automate FS LEFT tabbar, use this css mod instead:
#browser.fullscreen #tabs-container{ display: flex; position: fixed; top: 0; bottom: 0; left: 0; z-index: 9; flex-direction: column; background: var(--colorBg); transition: opacity .2s ease-out !important; } #browser.fullscreen #tabs-container:not(:focus-within):not(:hover) { transform:translateX(-100%); opacity: 0; transition: transform 0s .4s, opacity .35s ease-out 0s !important; } #browser.fullscreen #tabs-container .fullheight {right:-7px;} #browser.fullscreen #tabs-container .tab-strip { overflow-x: hidden; overflow-y: auto; }
Caveat: For some reason FS mode have a 7px deadzone all around the screen edge, so we have to move the pointer inward a bit after touching the LEFT screen edge to reveal the tabbar!
-
@dude99 said:
is this a "bug" or "feature"???
I think it's a buggy creature + β
Try this, it worked (once). Don't forget to do your edits to it.
(function () { function doMod() { let isModEnabled = false; let tabBar = document.querySelector('#tabs-container'); function scrollToTab(tabInfo) { if (isModEnabled) { let tab; if (tabInfo && tabInfo.tabId) tab = document.querySelector('#tab-' + tabInfo.tabId); else tab = document.querySelector('#tabs-container .tab-strip .tab.active'); if (tab) tab.scrollIntoViewIfNeeded(); } } function checkIsModEnabled() { vivaldi.prefs.get('vivaldi.tabs.visible', function(tabsVisible){ if (tabsVisible) vivaldi.prefs.get('vivaldi.tabs.bar.position', function(barPosition){ if (barPosition === 'left' || barPosition === 'right' || barPosition === 1 || barPosition === 2) isModEnabled = true; else isModEnabled = false; }); else isModEnabled = false; }); } checkIsModEnabled(); vivaldi.prefs.onChanged.addListener(function(pref){ if (pref.path === 'vivaldi.tabs.visible' || pref.path === 'vivaldi.tabs.bar.position') checkIsModEnabled(); }); vivaldi.windowPrivate.onFullscreen.addListener((fsId, fs) => { vivaldi.windowPrivate.getCurrentId(currId => { if (currId == fsId) { tabBar = document.querySelector('#tabs-container'); if (tabBar && document.body.contains(tabBar)) tabBar.addEventListener('mouseleave', scrollToTab); scrollToTab(); } }); }); chrome.tabs.onActivated.addListener(scrollToTab); if (tabBar && document.body.contains(tabBar)) tabBar.addEventListener('mouseleave', scrollToTab); scrollToTab(); } setTimeout(function wait() { let tabs = document.querySelector('#tabs-container'); if (tabs) doMod(); else setTimeout(wait, 300); }, 300); })();