@@ -2144,21 +2144,6 @@ export function detectTabActionFromNewPosition(tab, moveInfo = {}) {
21442144}
21452145
21462146
2147- function maintainTreeForUpdatedNativeTabGroups ( { windowId, groupId } , options = { } ) {
2148- let timer = maintainTreeForUpdatedNativeTabGroups . delayed . get ( groupId ) ;
2149- if ( timer )
2150- clearTimeout ( timer ) ;
2151- if ( options . justNow || ! shouldApplyAnimation ( ) ) {
2152- return maintainTreeForNativeTabGroups ( { windowId, groupId } ) ;
2153- }
2154- timer = setTimeout ( ( ) => {
2155- maintainTreeForUpdatedNativeTabGroups . delayed . delete ( groupId ) ;
2156- maintainTreeForNativeTabGroups ( { windowId, groupId } ) ;
2157- } , 100 ) ;
2158- maintainTreeForUpdatedNativeTabGroups . delayed . set ( groupId , timer ) ;
2159- }
2160- maintainTreeForUpdatedNativeTabGroups . delayed = new Map ( ) ;
2161-
21622147/*
21632148*************************************************************************
21642149Logic to maintain tree structure based on modified native tab groups
@@ -2183,7 +2168,8 @@ Firefox's native tab groups feature's basics:
21832168* When some of already grouped tabs are moved to another group, they will
21842169 be moved AFTER existing members of the destination group.
21852170
2186- TST should imitate Firefox's behavior, and should do more:
2171+ TST should imitate Firefox's behavior, and should do more with the method
2172+ maintainTreeForNativeTabGroup():
21872173
21882174* A tree should not be separated with multiple groups.
21892175 All member tabs in a tree should be grouped with a same tab group,
@@ -2197,14 +2183,22 @@ TST should imitate Firefox's behavior, and should do more:
21972183 they will be moved by Firefox. TST should DO NOTHING EXTRA ON THIS
21982184 CASE, because tree structure of moved tabs are automatically
21992185 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.
2186+
2187+ And, what we should do when TST is activated and detects a tree is
2188+ separated to multiple groups? For example:
2189+
2190+ * tab1
2191+ * tab2 [group1]
2192+ * tab3 [group1]
2193+ * tab4
2194+ * tab5 [group2]
2195+ * tab6 [group2]
2196+
2197+ On this case we need to move only tab1 and tab4, otherwise moving of
2198+ already grouped tabs will break those groups. The method
2199+ maintainTreeForNativeTabGroup() does that too.
22062200*/
2207- async function maintainTreeForNativeTabGroups ( { windowId, groupId } ) {
2201+ async function maintainTreeForNativeTabGroup ( { windowId, groupId } ) {
22082202 const win = TabsStore . windows . get ( windowId ) ;
22092203
22102204 const members = Tab . getNativeGroupMemberTabs ( { windowId, groupId } ) ;
@@ -2214,63 +2208,114 @@ async function maintainTreeForNativeTabGroups({ windowId, groupId }) {
22142208 return ;
22152209 }
22162210
2217- log ( 'maintainTreeForNativeTabGroups: wholeTree = ' , wholeTree ) ;
2211+ log ( `maintainTreeForNativeTabGroup: groupId = ${ groupId } , wholeTree = ` , ( ) => wholeTree . map ( tab => `# ${ tab . id } (@ ${ tab . index } )[ ${ tab . groupId } ]` ) ) ;
22182212
2219- const membersStructure = TreeBehavior . getTreeStructureFromTabs ( members ) ;
2220- await detachTabsFromTree ( members , {
2221- partial : true ,
2222- } ) ;
2213+ const membersAndStructures = new Map ( ) ;
2214+ const groupedTabs = new Set ( ) ;
2215+ const others = [ ] ;
2216+ let lastMember = null ;
2217+ for ( const tab of wholeTree ) {
2218+ if ( tab . groupId == - 1 ) {
2219+ others . push ( tab ) ;
2220+ }
2221+ else {
2222+ groupedTabs . add ( tab ) ;
2223+ const membersAndStructure = membersAndStructures . get ( tab . groupId ) || { members : [ ] } ;
2224+ membersAndStructure . members . push ( tab ) ;
2225+ membersAndStructures . set ( tab . groupId , membersAndStructure ) ;
2226+ lastMember = tab ;
2227+ }
2228+ }
2229+ for ( const [ groupId , membersAndStructure ] of membersAndStructures . entries ( ) ) {
2230+ log ( `maintainTreeForNativeTabGroup: groupId = ${ groupId } , members = ` , ( ) => membersAndStructure . members . map ( tab => `#${ tab . id } (@${ tab . index } )[${ tab . groupId } ]` ) ) ;
2231+ membersAndStructure . structure = TreeBehavior . getTreeStructureFromTabs ( membersAndStructure . members ) ,
2232+ await detachTabsFromTree ( members , {
2233+ partial : true ,
2234+ } ) ;
2235+ }
22232236
2224- const membersSet = new Set ( members ) ;
2225- const others = wholeTree . filter ( tab => ! membersSet . has ( tab ) ) ;
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.' ) ;
2237+ log ( 'maintainTreeForNativeTabGroup: others = ' , ( ) => others . map ( tab => `#${ tab . id } (@${ tab . index } )[${ tab . groupId } ]` ) , `, lastMember = #${ lastMember . id } (@${ lastMember . index } )` ) ;
2238+
2239+ if ( others . length == 0 ) {
2240+ log ( 'maintainTreeForNativeTabGroup: there is no other tabs need to be moved, so we do nothing.' ) ;
22292241 return ;
22302242 }
22312243
22322244 for ( const other of others ) {
22332245 win . internallyMovingTabsForUpdatedNativeTabGroups . add ( other . id ) ;
22342246 }
22352247 const othersStructure = TreeBehavior . getTreeStructureFromTabs ( others ) ;
2248+ log ( 'maintainTreeForNativeTabGroup: othersStructure = ' , othersStructure ) ;
2249+ await detachTabsFromTree ( others ) ;
22362250 await moveTabs ( others , {
2237- insertAfter : members [ members . length - 1 ] ,
2251+ insertAfter : lastMember ,
22382252 insertBefore : others [ others . length - 1 ] . unsafeNextTab ,
22392253 } ) ;
2254+ log ( 'maintainTreeForNativeTabGroup: moved others = ' , others . map ( tab => `#${ tab . id } (@${ tab . index } )[${ tab . groupId } ]` ) ) ;
22402255
22412256 await Promise . race ( [
22422257 new Promise ( ( resolve , _reject ) => {
2243- const resolvers = maintainTreeForNativeTabGroups . resolversForWindow . get ( windowId ) || [ ] ;
2258+ const resolvers = maintainTreeForNativeTabGroup . resolversForWindow . get ( windowId ) || [ ] ;
22442259 resolvers . push ( resolve ) ;
2245- maintainTreeForNativeTabGroups . resolversForWindow . set ( windowId , resolvers ) ;
2260+ maintainTreeForNativeTabGroup . resolversForWindow . set ( windowId , resolvers ) ;
22462261 } ) ,
22472262 wait ( 500 ) ,
22482263 ] ) ;
2249- maintainTreeForNativeTabGroups . resolversForWindow . delete ( windowId ) ;
2264+ maintainTreeForNativeTabGroup . resolversForWindow . delete ( windowId ) ;
22502265
22512266 for ( const other of others ) {
22522267 win . internallyMovingTabsForUpdatedNativeTabGroups . delete ( other . id ) ;
22532268 }
2254- applyTreeStructureToTabs ( members , membersStructure ) ;
2269+ for ( const { members, structure } of membersAndStructures . values ( ) ) {
2270+ applyTreeStructureToTabs ( members , structure ) ;
2271+ }
22552272 applyTreeStructureToTabs ( others , othersStructure ) ;
22562273 browser . tabs . ungroup ( others . map ( tab => tab . id ) ) ;
22572274}
2258- maintainTreeForNativeTabGroups . resolversForWindow = new Map ( ) ;
2275+ maintainTreeForNativeTabGroup . resolversForWindow = new Map ( ) ;
22592276
2260- Tab . onNativeGroupModified . addListener ( tab => {
2261- const win = TabsStore . windows . get ( tab . windowId ) ;
2262- if ( win . internallyMovingTabsForUpdatedNativeTabGroups . has ( tab . id ) ) {
2263- window . requestAnimationFrame ( ( ) => {
2264- const resolvers = maintainTreeForNativeTabGroups . resolversForWindow . get ( tab . windowId ) || [ ] ;
2265- maintainTreeForNativeTabGroups . resolversForWindow . delete ( tab . windowId ) ;
2266- for ( const resolver of resolvers ) {
2267- resolver ( ) ;
2268- }
2277+ function reserveToMaintainTreeForUpdatedNativeTabGroup ( { windowId, groupId } , options = { } ) {
2278+ let timer = reserveToMaintainTreeForUpdatedNativeTabGroup . delayed . get ( groupId ) ;
2279+ if ( timer )
2280+ clearTimeout ( timer ) ;
2281+ if ( options . justNow || ! shouldApplyAnimation ( ) ) {
2282+ return maintainTreeForNativeTabGroup ( { windowId, groupId } ) ;
2283+ }
2284+ timer = setTimeout ( ( ) => {
2285+ reserveToMaintainTreeForUpdatedNativeTabGroup . delayed . delete ( groupId ) ;
2286+ maintainTreeForNativeTabGroup ( { windowId, groupId } ) ;
2287+ } , 100 ) ;
2288+ reserveToMaintainTreeForUpdatedNativeTabGroup . delayed . set ( groupId , timer ) ;
2289+ }
2290+ reserveToMaintainTreeForUpdatedNativeTabGroup . delayed = new Map ( ) ;
2291+
2292+ export async function startToMaintainTreeForNativeTabGroups ( ) {
2293+ // fixup mismatched tree structure and tab groups constructed while TST is disabled
2294+ const groups = await browser . tabGroups . query ( { } ) ;
2295+ for ( const group of groups ) {
2296+ await maintainTreeForNativeTabGroup ( {
2297+ windowId : group . windowId ,
2298+ groupId : group . id ,
22692299 } ) ;
2270- return ;
22712300 }
2272- maintainTreeForUpdatedNativeTabGroups ( tab ) ;
2273- } ) ;
2301+
2302+ // after all we start tracking of dynamic changes of tab groups
2303+ Tab . onNativeGroupModified . addListener ( tab => {
2304+ const win = TabsStore . windows . get ( tab . windowId ) ;
2305+ if ( win . internallyMovingTabsForUpdatedNativeTabGroups . has ( tab . id ) ) {
2306+ window . requestAnimationFrame ( ( ) => {
2307+ const resolvers = maintainTreeForNativeTabGroup . resolversForWindow . get ( tab . windowId ) || [ ] ;
2308+ maintainTreeForNativeTabGroup . resolversForWindow . delete ( tab . windowId ) ;
2309+ for ( const resolver of resolvers ) {
2310+ resolver ( ) ;
2311+ }
2312+ } ) ;
2313+ return ;
2314+ }
2315+ reserveToMaintainTreeForUpdatedNativeTabGroup ( tab ) ;
2316+ } ) ;
2317+ }
2318+
22742319
22752320
22762321//===================================================================
0 commit comments