Tab Stack Data in the "vivaldi" Object
-
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. -
I used Otto tabs until Vivaldi version 6.7 and I still have it installed for removing duplicate tabs.
Could you add this feature and make the Mod even more fantastic?
-
@barbudo2005
I don't need that functionality and would not implement that functionality in a mod if it could be accomplished with existing extensions. -
Ok. You are absolutely right and it was a mistake to ask you.
-
@nafumofu
Thank you for your efforts.
You are a legend.
Btw, I wonder why but auto-stack doesn't work in workspace.
Where was my mistake?このModを有難うございます!
個別のワークスペースだと、自動スタックがされないのですが、
設定を何か間違えているのでしょうか?