@@ -2149,17 +2149,62 @@ function maintainTreeForUpdatedNativeTabGroups({ windowId, groupId }, options =
21492149 if ( timer )
21502150 clearTimeout ( timer ) ;
21512151 if ( options . justNow || ! shouldApplyAnimation ( ) ) {
2152- return maintainTreeForUpdatedNativeTabGroupsNow ( { windowId, groupId } ) ;
2152+ return maintainTreeForNativeTabGroups ( { windowId, groupId } ) ;
21532153 }
21542154 timer = setTimeout ( ( ) => {
21552155 maintainTreeForUpdatedNativeTabGroups . delayed . delete ( groupId ) ;
2156- maintainTreeForUpdatedNativeTabGroupsNow ( { windowId, groupId } ) ;
2156+ maintainTreeForNativeTabGroups ( { windowId, groupId } ) ;
21572157 } , 100 ) ;
21582158 maintainTreeForUpdatedNativeTabGroups . delayed . set ( groupId , timer ) ;
21592159}
21602160maintainTreeForUpdatedNativeTabGroups . delayed = new Map ( ) ;
21612161
2162- async function maintainTreeForUpdatedNativeTabGroupsNow ( { windowId, groupId } ) {
2162+ /*
2163+ *************************************************************************
2164+ Logic to maintain tree structure based on modified native tab groups
2165+ *************************************************************************
2166+
2167+ Firefox's native tab groups feature's basics:
2168+
2169+ * When tabs are newly grouped, they are gathered to THE PLACE OF THE TAB
2170+ YOU OPENED THE CONTEXT MENU ON.
2171+ * When some of already grouped tabs are grouped with another new group,
2172+ a new group will be placed BEFORE THE SOURCE GROUP OF THE CONTEXT TAB
2173+ and all member tabs will be gathered there.
2174+ * When tabs in different groups are grouped with another new group, the
2175+ new group will be placed BEFORE THE SOURCE GROUP OF THE CONTEXT TAB.
2176+ * When some of already grouped tabs are ungrouped, they will be moved
2177+ AFTER the source group.
2178+ * When all member tabs are ungrouped, they will be there and just
2179+ ungrouped.
2180+ * When tabs in different groups are ungrouped, ungrouped tabs will be
2181+ placed AFTER EACH SOURCE GROUP. In other words, ungrouped tabs won't
2182+ be gathered.
2183+ * When some of already grouped tabs are moved to another group, they will
2184+ be moved AFTER existing members of the destination group.
2185+
2186+ TST should imitate Firefox's behavior, and should do more:
2187+
2188+ * A tree should not be separated with multiple groups.
2189+ All member tabs in a tree should be grouped with a same tab group,
2190+ otherwise all members are ungrouped.
2191+ * When some member tabs in a tree are grouped, they need to be DETACHED
2192+ FROM THE ORIGINAL TREE and PLACED BEFORE THE SOURCE TREE.
2193+ Thus TST need to REARRANGE INVOLVED TABS.
2194+ * However, moving grouped tabs may break the native tab group,
2195+ so TST need to move OTHER TABS.
2196+ * When already grouped tabs are newly grouped to another new group,
2197+ they will be moved by Firefox. TST should DO NOTHING EXTRA ON THIS
2198+ CASE, because tree structure of moved tabs are automatically
2199+ maintained.
2200+ * When TST is activated and detects a tree is separated to multiple
2201+ groups,
2202+ TST should separate the tree to multiple parts for each group.
2203+ This operation will be done based on native tab groups.
2204+ Member tabs of each group will be detached from the source tree, and
2205+ this operation will be done for all groups repeatedly.
2206+ */
2207+ async function maintainTreeForNativeTabGroups ( { windowId, groupId } ) {
21632208 const win = TabsStore . windows . get ( windowId ) ;
21642209
21652210 const members = Tab . getNativeGroupMemberTabs ( { windowId, groupId } ) ;
@@ -2169,7 +2214,7 @@ async function maintainTreeForUpdatedNativeTabGroupsNow({ windowId, groupId }) {
21692214 return ;
21702215 }
21712216
2172- log ( 'maintainTreeForUpdatedNativeTabGroupsNow : wholeTree = ' , wholeTree ) ;
2217+ log ( 'maintainTreeForNativeTabGroups : wholeTree = ' , wholeTree ) ;
21732218
21742219 const membersStructure = TreeBehavior . getTreeStructureFromTabs ( members ) ;
21752220 await detachTabsFromTree ( members , {
@@ -2178,7 +2223,12 @@ async function maintainTreeForUpdatedNativeTabGroupsNow({ windowId, groupId }) {
21782223
21792224 const membersSet = new Set ( members ) ;
21802225 const others = wholeTree . filter ( tab => ! membersSet . has ( tab ) ) ;
2181- log ( 'maintainTreeForUpdatedNativeTabGroupsNow: others = ' , others ) ;
2226+ log ( 'maintainTreeForNativeTabGroups: others = ' , others ) ;
2227+ if ( others . some ( other => other . groupId != - 1 ) ) {
2228+ log ( 'maintainTreeForNativeTabGroups: others are already grouped and moved by Firefox, so we need to do nothing anymore.' ) ;
2229+ return ;
2230+ }
2231+
21822232 for ( const other of others ) {
21832233 win . internallyMovingTabsForUpdatedNativeTabGroups . add ( other . id ) ;
21842234 }
@@ -2190,13 +2240,13 @@ async function maintainTreeForUpdatedNativeTabGroupsNow({ windowId, groupId }) {
21902240
21912241 await Promise . race ( [
21922242 new Promise ( ( resolve , _reject ) => {
2193- const resolvers = maintainTreeForUpdatedNativeTabGroupsNow . resolversForWindow . get ( windowId ) || [ ] ;
2243+ const resolvers = maintainTreeForNativeTabGroups . resolversForWindow . get ( windowId ) || [ ] ;
21942244 resolvers . push ( resolve ) ;
2195- maintainTreeForUpdatedNativeTabGroupsNow . resolversForWindow . set ( windowId , resolvers ) ;
2245+ maintainTreeForNativeTabGroups . resolversForWindow . set ( windowId , resolvers ) ;
21962246 } ) ,
21972247 wait ( 500 ) ,
21982248 ] ) ;
2199- maintainTreeForUpdatedNativeTabGroupsNow . resolversForWindow . delete ( windowId ) ;
2249+ maintainTreeForNativeTabGroups . resolversForWindow . delete ( windowId ) ;
22002250
22012251 for ( const other of others ) {
22022252 win . internallyMovingTabsForUpdatedNativeTabGroups . delete ( other . id ) ;
@@ -2205,14 +2255,14 @@ async function maintainTreeForUpdatedNativeTabGroupsNow({ windowId, groupId }) {
22052255 applyTreeStructureToTabs ( others , othersStructure ) ;
22062256 browser . tabs . ungroup ( others . map ( tab => tab . id ) ) ;
22072257}
2208- maintainTreeForUpdatedNativeTabGroupsNow . resolversForWindow = new Map ( ) ;
2258+ maintainTreeForNativeTabGroups . resolversForWindow = new Map ( ) ;
22092259
22102260Tab . onNativeGroupModified . addListener ( tab => {
22112261 const win = TabsStore . windows . get ( tab . windowId ) ;
22122262 if ( win . internallyMovingTabsForUpdatedNativeTabGroups . has ( tab . id ) ) {
22132263 window . requestAnimationFrame ( ( ) => {
2214- const resolvers = maintainTreeForUpdatedNativeTabGroupsNow . resolversForWindow . get ( tab . windowId ) || [ ] ;
2215- maintainTreeForUpdatedNativeTabGroupsNow . resolversForWindow . delete ( tab . windowId ) ;
2264+ const resolvers = maintainTreeForNativeTabGroups . resolversForWindow . get ( tab . windowId ) || [ ] ;
2265+ maintainTreeForNativeTabGroups . resolversForWindow . delete ( tab . windowId ) ;
22162266 for ( const resolver of resolvers ) {
22172267 resolver ( ) ;
22182268 }
0 commit comments