Tab Stack Data in the "vivaldi" Object
-
@Daemonicvs I'm going to throw out a totally random guess and say it has something to do with chrome implementing their own sort of tab grouping feature.
-
@benlenem said in Tab Stack Data in the "vivaldi" Object:
Hi,
I just released Otto Tabs, a small chromium based extension to automatically group/stack your tabs when using same domain and delete duplicates. Nothing fancy, you can check it out
I used the
tab.extData
trick @Njol talked about to make it work with Vivaldi.https://github.com/Benlenem/chrome-otto-tabs
Your feedback is welcome !
Hello, after being removed few months ago, I published the extension again here : https://chrome.google.com/webstore/detail/otto-tabs/pjgajilkdijnbfmglfbpnenocpajmdlb
Have fun
-
@benlenem
Hello, I just found your extension, and it does exactly what I want. Thanks for your work! I also like that the automatic stack works only within the same window.Just a question. Is there a way to focus directly to the tab after it is moved? I think that looking for the correct stack after opening a link is a bit counterintuitive.
Cheers! -
@benlenem I believe that Otto tabs is one of my favorite Vivaldi extensions. I really appreciate your work!
Just in case, it looks like
tab.extData
was renamed totab.vivExtData
recently, breaking Otto tabs grouping functionality. I made a PR to address that - please find it in the repo: https://github.com/borsini/chrome-otto-tabs/pull/11 -
Following this SO post, I can confirm that
vivExtData
has been removed in latest versions.Unfortunately the
chrome.tabs.group
function does nothing on Vivaldi Thus no more support for tab grouping with Otto Tabs. -
With the patched (forked) versión of @grigorye :
https://forum.vivaldi.net/topic/56025/auto-group-tab-stacks-by-domain/41?_=1714408532749
Otto tabs works, but has a problem in Vivaldi forum (it appears that the tabs are separated from the tab stacks and then inserted, and I think the explanation is that the URL changes as you scroll) and there's a serious compatibility issue with Workspaces.
Could you do a versión only for Vivaldi?
-
Just out of curiosity, what would be your explanation why @benlenem says that "Unfortunately the chrome.tabs.group function does nothing on Vivaldi Thus no more support for tab grouping with Otto Tabs", but your patched version does group tabs in stacked tabs in Vivaldi?
@benlenem changed the target:
"Compatibility
Otto Tabs works with all chromium based browsers that implement the chrome.tabs api.
Tested on Chrome 124.0.6367.119, Opera 109.0.5097.68, Brave 1.65.126"
-
@barbudo2005 I have no clue, the only guess that I can make is that chrome.tabs.group was never used on Vivaldi - there was Vivaldi-specific implementation in place, that was dropped from upstream due to no way to tell Vivaldi apart from Chrome (the thing that was broken in 6.7). Hence the (Vivaldi-only) fork still works, but upstream doesn't (if I get you correctly).
-
So if I understand you correctly, if someone would make a version just for Vivaldi, taking out the Chrome functionality, and could fix the problems with scrolling and Workspaces compatibility, then we could have a version that would work well with Vivaldi?
-
@barbudo2005 Well, if I guess the reasoning for removal of Vivaldi support from the upstream correctly, yes.
-
I have created an automatic tab stacking mod.
It is working well as far as I have tested it for a few hours.code
(async () => { 'use strict'; const config = { // デフォルト以外のワークスペースで自動タブスタックを使用する (true: 有効, false: 無効) // Use automatic tab stacking in non-default workspaces (true: enable, false: disable) workspace: false, // サブドメインごとにタブをスタックする (true: 有効, false: 無効) // Stack tabs by subdomain (true: enable, false: disable) subdomain: true, // タブスタック名を自動的に変更する (0: 無効, 1: ホスト名を使用, 2: ベースドメインから生成) // Automatically change tab stack names (0: disabled, 1: use hostname, 2: generated from base domain) stackname: 0, // 自動タブスタックの対象とするホストのルール (完全一致もしくは正規表現) // Rules for hosts to be included in the automatic tab stack (exact match or regular expression) includes: [], // 自動タブスタックから除外するホストのルール (完全一致もしくは正規表現) // Rules for hosts to be excluded from the automatic tab stack (exact match or regular expression) excludes: [ // 'www.example.com', // /^(.+\.)?example\.net$/, ], }; const addTabGroup = async (tabId, groupId) => { const tab = await chrome.tabs.get(tabId); const extData = JSON.parse(tab.vivExtData); extData.group = groupId; await chrome.tabs.update(tabId, { vivExtData: JSON.stringify(extData) }); }; const getUrlFragments = (url) => vivaldi.utilities.getUrlFragments(url); const getBaseDomain = (url) => { const urlFragments = getUrlFragments(url); return urlFragments.host.match(`([^.]+\\.${ urlFragments.tld })$`)?.[1] || urlFragments.host; }; const getHostname = (url) => config.subdomain ? getUrlFragments(url).host : getBaseDomain(url); const matchHostRule = (url, rule) => { const hostname = getUrlFragments(url).host; return rule instanceof RegExp ? rule.test(hostname) : hostname === rule; }; const getTabInfo = async (tabId) => { const tab = await chrome.tabs.get(tabId); if (tab.id !== -1) { tab.vivExtData = JSON.parse(tab.vivExtData); return tab; } }; const getTabStore = async () => { const tabStore = {}; const tabs = (await chrome.tabs.query({ currentWindow: true })) .filter(tab => tab.id !== -1) .map(tab => Object.assign(tab, { vivExtData: JSON.parse(tab.vivExtData) })) .filter(tab => !tab.pinned) .filter(tab => !tab.vivExtData.panelId) .filter(tab => !config.includes.length ? true : config.includes.find(rule => matchHostRule(tab.url, rule))) .filter(tab => !config.excludes.find(rule => matchHostRule(tab.url, rule))); const workspaces = Object.groupBy(tabs, (tab) => tab.vivExtData.workspaceId); for (const [workspaceId, tabs] of Object.entries(workspaces)) { tabStore[workspaceId] = Object.groupBy(tabs, (tab) => tab.vivExtData.group); } return tabStore; }; const getTabGroupMap = (tabStore) => { const tabGroupMap = {}; for (const [workspaceId, groups] of Object.entries(tabStore)) { tabGroupMap[workspaceId] = {}; for (const [groupId, tabs] of Object.entries(groups)) { const hostnames = Object.keys(Object.groupBy(tabs, (tab) => getHostname(tab.url))); if (hostnames.length === 1 && groupId && groupId !== 'undefined') { tabGroupMap[workspaceId][hostnames[0]] ??= []; tabGroupMap[workspaceId][hostnames[0]].push(groupId); } } } return tabGroupMap; }; const groupingTabs = async (targetTab) => { const tabStore = await getTabStore(); const tabGroupMap = getTabGroupMap(tabStore); for (const [workspaceId, groups] of Object.entries(tabStore)) { if (!config.workspace && workspaceId !== 'undefined') continue; if (String(targetTab.vivExtData.workspaceId) !== workspaceId) continue; const tabGroups = {}; for (const tabs of Object.values(groups)) { for (const tab of tabs) { const hostname = getHostname(tab.url); tabGroupMap[workspaceId][hostname] ??= [crypto.randomUUID()]; const groupId = tabGroupMap[workspaceId][hostname].sort()[0]; tabGroups[groupId] ??= []; tabGroups[groupId].push(tab); } } for (const [groupId, tabs] of Object.entries(tabGroups)) { if (getHostname(targetTab.url) === getHostname(tabs[0].url)) { let tabIndex = (await getTabInfo(tabs[0].id)).index; if (config.stackname) { const stackNameMap = await vivaldi.prefs.get('vivaldi.tabs.stacking.name_map'); let stackname; switch (config.stackname) { case 1: stackname = getHostname(targetTab.url); break; case 2: stackname = getBaseDomain(targetTab.url).split('.')[0]; stackname = stackname.charAt(0).toUpperCase() + stackname.slice(1); break; } await vivaldi.prefs.set({ path: 'vivaldi.tabs.stacking.name_map', value: Object.assign(stackNameMap, { [groupId]: stackname }), }); } for (const tab of tabs) { if (tab.vivExtData.group !== groupId) { addTabGroup(tab.id, groupId); } chrome.tabs.move(tab.id, { index: tabIndex }); tabIndex++; } } } } } chrome.webNavigation.onCommitted.addListener(async (details) => { const tab = await getTabInfo(details.tabId); if (tab && !tab.pinned && !tab.vivExtData.panelId && details.frameType === 'outermost_frame') { setTimeout(() => { groupingTabs(tab); }, 100); } }); })();
-
-
Thank you very much.
Could you add to work in same host but different subdomains?
This links:
https://huellalibrosicc.blogspot.com
-
For your fantastic Mod to be used by more people please open a new Thread, called "Group tabs by domain".
Thanks again.
-
@barbudo2005
I have modified the code to add a new setting.
Changingsubdomain: true
tosubdomain: false
will stack tabs for different subdomains of the same host. -
Hi,
You can add a clone or own's version to the Top of the Code to provide Mod's Info / Tracking:/* * Site Security Box Favicons (a mod for Vivaldi) * https://forum.vivaldi.net/topic/23813/site-security-box-favicons-mod * Written by LonM, kichrot * No Copyright Reserved * This mod takes the favicon from a tab and places it into the address bar site info box * Assumes presence of both the tab bar and the address bar */
/* Window Border | unMaximised version -------------------------- HTML | CSS | FORMS | JAVA | jQUERY - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Description: Window Border | unMaximised version Filename: xxxxxx.css Author: slausage Topic: https://forum.vivaldi.net/topic/5603/border-around-browser-window/20 ----------------------------------------------------------------- */
/* ---------------------------------------------------------------- HTML | CSS | FORMS | JAVA | jQUERY - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Description: Name [Project] Filename: xxxxxx.css Author: Topic: ----------------------------------------------------------------- */
Thx
-
You came at the right time to save us from the monotony of not having the operation automatically, as it should always be. Thank you very much again.
What does it mean?:
workspace: false
-
@barbudo2005
This setting enables or disables automatic tab stacking within a workspace. -
Can you please give me an example to clarify what is involved?
-
@barbudo2005
The automatic tab stack will work even if you switch to a non-default workspace.Sorry. It is difficult to explain using machine translation.
Please actually change the settings and try it out.