@@ -66,22 +66,27 @@ browser.windows.onRemoved.addListener(windowId => {
6666} ) ;
6767
6868export default class Tab {
69- constructor ( tab ) {
70- const alreadyTracked = Tab . get ( tab . id ) ;
69+ constructor ( raw ) {
70+ const alreadyTracked = Tab . get ( raw . id ) ;
7171 if ( alreadyTracked )
7272 return alreadyTracked . $TST ;
7373
74- log ( `tab ${ dumpTab ( tab ) } is newly tracked: ` , tab ) ;
74+ log ( `tab ${ dumpTab ( raw ) } is newly tracked: ` , raw ) ;
75+
76+ raw . $TST = this ;
77+ this . raw = raw ;
78+ this . id = raw . id ;
79+
80+ const tab = this . tab ;
7581
76- tab . $TST = this ;
77- this . tab = tab ;
78- this . id = tab . id ;
7982 this . trackedAt = Date . now ( ) ;
80- this . opened = new Promise ( ( resolve , reject ) => {
81- const resolvers = mOpenedResolvers . get ( tab . id ) || new Set ( ) ;
82- resolvers . add ( { resolve, reject } ) ;
83- mOpenedResolvers . set ( tab . id , resolvers ) ;
84- } ) ;
83+ this . opened = tab ?
84+ new Promise ( ( resolve , reject ) => {
85+ const resolvers = mOpenedResolvers . get ( tab . id ) || new Set ( ) ;
86+ resolvers . add ( { resolve, reject } ) ;
87+ mOpenedResolvers . set ( tab . id , resolvers ) ;
88+ } ) :
89+ Promise . resolve ( true ) ;
8590
8691 // We should not change the shape of the object, so temporary data should be held in this map.
8792 this . temporaryMetadata = new Map ( ) ;
@@ -138,59 +143,65 @@ export default class Tab {
138143 this . onUniqueIdGenerated = resolve ;
139144 } ) ;
140145
141- TabsStore . tabs . set ( tab . id , tab ) ;
146+ if ( tab ) {
147+ this . index = tab . index ;
142148
143- const win = TabsStore . windows . get ( tab . windowId ) || new Window ( tab . windowId ) ;
144- win . trackTab ( tab ) ;
149+ TabsStore . tabs . set ( tab . id , tab ) ;
145150
146- // Don't update indexes here, instead Window.prototype.trackTab()
147- // updates indexes because indexes are bound to windows.
148- // TabsStore.updateIndexesForTab(tab);
151+ const win = TabsStore . windows . get ( tab . windowId ) || new Window ( tab . windowId ) ;
152+ win . trackTab ( tab ) ;
149153
150- if ( tab . active ) {
151- TabsStore . activeTabInWindow . set ( tab . windowId , tab ) ;
152- TabsStore . activeTabsInWindow . get ( tab . windowId ) . add ( tab ) ;
153- }
154- else {
155- TabsStore . activeTabsInWindow . get ( tab . windowId ) . delete ( tab ) ;
156- }
154+ // Don't update indexes here, instead Window.prototype.trackTab()
155+ // updates indexes because indexes are bound to windows.
156+ // TabsStore.updateIndexesForTab(tab);
157157
158- const incompletelyTrackedTabsPerWindow = mIncompletelyTrackedTabs . get ( tab . windowId ) || new Set ( ) ;
159- incompletelyTrackedTabsPerWindow . add ( tab ) ;
160- mIncompletelyTrackedTabs . set ( tab . windowId , incompletelyTrackedTabsPerWindow ) ;
161- this . promisedUniqueId . then ( ( ) => {
162- incompletelyTrackedTabsPerWindow . delete ( tab ) ;
163- Tab . onTracked . dispatch ( tab ) ;
164- } ) ;
158+ if ( tab . active ) {
159+ TabsStore . activeTabInWindow . set ( tab . windowId , tab ) ;
160+ TabsStore . activeTabsInWindow . get ( tab . windowId ) . add ( tab ) ;
161+ }
162+ else {
163+ TabsStore . activeTabsInWindow . get ( tab . windowId ) . delete ( tab ) ;
164+ }
165+
166+ const incompletelyTrackedTabsPerWindow = mIncompletelyTrackedTabs . get ( tab . windowId ) || new Set ( ) ;
167+ incompletelyTrackedTabsPerWindow . add ( tab ) ;
168+ mIncompletelyTrackedTabs . set ( tab . windowId , incompletelyTrackedTabsPerWindow ) ;
169+ this . promisedUniqueId . then ( ( ) => {
170+ incompletelyTrackedTabsPerWindow . delete ( tab ) ;
171+ Tab . onTracked . dispatch ( tab ) ;
172+ } ) ;
173+ }
165174
166175 // We should initialize private properties with blank value for better performance with a fixed shape.
167176 this . delayedInheritSoundStateFromChildren = null ;
168177 }
169178
170179 destroy ( ) {
171- mPromisedTrackedTabs . delete ( `${ this . id } :true` ) ;
172- mPromisedTrackedTabs . delete ( `${ this . id } :false` ) ;
180+ if ( this . tab ) {
181+ mPromisedTrackedTabs . delete ( `${ this . id } :true` ) ;
182+ mPromisedTrackedTabs . delete ( `${ this . id } :false` ) ;
173183
174- Tab . onDestroyed . dispatch ( this . tab ) ;
175- this . detach ( ) ;
184+ Tab . onDestroyed . dispatch ( this . tab ) ;
185+ this . detach ( ) ;
176186
177- if ( this . temporaryMetadata . has ( 'reservedCleanupNeedlessGroupTab' ) ) {
178- clearTimeout ( this . temporaryMetadata . get ( 'reservedCleanupNeedlessGroupTab' ) ) ;
179- this . temporaryMetadata . delete ( 'reservedCleanupNeedlessGroupTab' ) ;
180- }
187+ if ( this . temporaryMetadata . has ( 'reservedCleanupNeedlessGroupTab' ) ) {
188+ clearTimeout ( this . temporaryMetadata . get ( 'reservedCleanupNeedlessGroupTab' ) ) ;
189+ this . temporaryMetadata . delete ( 'reservedCleanupNeedlessGroupTab' ) ;
190+ }
181191
182- TabsStore . tabs . delete ( this . id ) ;
183- if ( this . uniqueId )
184- TabsStore . tabsByUniqueId . delete ( this . uniqueId . id ) ;
192+ TabsStore . tabs . delete ( this . id ) ;
193+ if ( this . uniqueId )
194+ TabsStore . tabsByUniqueId . delete ( this . uniqueId . id ) ;
185195
186- TabsStore . removeTabFromIndexes ( this . tab ) ;
196+ TabsStore . removeTabFromIndexes ( this . tab ) ;
197+ }
187198
188199 if ( this . element &&
189200 this . element . parentNode )
190201 this . element . parentNode . removeChild ( this . element ) ;
191202 this . unbindElement ( ) ;
192- // this.tab .$TST = null; // tab .$TST is used by destruction processes.
193- this . tab = null ;
203+ // this.raw .$TST = null; // raw .$TST is used by destruction processes.
204+ this . raw = null ;
194205 this . promisedUniqueId = null ;
195206 this . uniqueId = null ;
196207 this . destroyed = true ;
@@ -287,6 +298,28 @@ export default class Tab {
287298 } ) ;
288299 }
289300
301+ get type ( ) {
302+ return 'color' in this . raw ? 'group' : 'tab' ;
303+ }
304+
305+ get renderingId ( ) {
306+ return `${ this . type } :${ this . id } ` ;
307+ }
308+
309+ get tab ( ) {
310+ if ( 'color' in this . raw ) { // native tab group
311+ return null ;
312+ }
313+ return this . raw ;
314+ }
315+
316+ get rawGroup ( ) {
317+ if ( 'color' in this . raw ) {
318+ return this . raw ;
319+ }
320+ return null ;
321+ }
322+
290323
291324 //===================================================================
292325 // status of tab
@@ -596,7 +629,7 @@ export default class Tab {
596629 }
597630
598631 get defaultTooltipText ( ) {
599- return this . cookieStoreName ? `${ this . tab . title } - ${ this . cookieStoreName } ` : this . tab . title ;
632+ return this . cookieStoreName ? `${ this . raw . title } - ${ this . cookieStoreName } ` : this . raw . title ;
600633 }
601634
602635 generateTooltipText ( ) {
@@ -617,12 +650,12 @@ export default class Tab {
617650 return this . cookieStoreName ?
618651 `<span class="title-line"
619652 ><span class="title"
620- >${ sanitizeForHTMLText ( this . tab . title ) } </span
653+ >${ sanitizeForHTMLText ( this . raw . title ) } </span
621654 ><span class="cookieStoreName"
622655 >${ sanitizeForHTMLText ( this . cookieStoreName ) } </span></span>` :
623656 `<span class="title-line"
624657 ><span class="title"
625- >${ sanitizeForHTMLText ( this . tab . title ) } </span></span>` ;
658+ >${ sanitizeForHTMLText ( this . raw . title ) } </span></span>` ;
626659 }
627660
628661 generateTooltipHtmlWithDescendants ( ) {
@@ -1919,6 +1952,19 @@ export default class Tab {
19191952 }
19201953
19211954
1955+ onNativeGroupModified ( ) {
1956+ if ( this . tab . groupId == - 1 ) {
1957+ TabsStore . removeNativelyGroupedTab ( this . tab ) ;
1958+ }
1959+ else {
1960+ TabsStore . addNativelyGroupedTab ( this . tab ) ;
1961+ }
1962+
1963+ const win = TabsStore . windows . get ( this . tab . windowId ) ;
1964+ win . updateNativeTabGroupItem ( this . tab . groupId ) ;
1965+ }
1966+
1967+
19221968 setAttribute ( attribute , value ) {
19231969 if ( this . element )
19241970 this . element . setAttribute ( attribute , value ) ;
@@ -2910,12 +2956,31 @@ Tab.getSelectedTabs = (windowId = null, options = {}) => {
29102956} ;
29112957
29122958Tab . getVirtualScrollRenderableTabs = ( windowId = null ) => {
2913- return TabsStore . queryAll ( {
2959+ const tabs = TabsStore . queryAll ( {
29142960 windowId,
29152961 tabs : TabsStore . getTabsMap ( TabsStore . virtualScrollRenderableTabsInWindow , windowId ) ,
29162962 skipMatching : true ,
29172963 ordered : true ,
29182964 } ) ;
2965+ if ( TabsStore . nativelyGroupedTabsInWindow . get ( windowId ) . size == 0 ) {
2966+ return tabs ;
2967+ }
2968+
2969+ const win = TabsStore . windows . get ( windowId ) ;
2970+ const mixedTabs = [ ] ;
2971+ let previousGroupId = - 1 ;
2972+ for ( const tab of tabs ) {
2973+ if ( tab . groupId != previousGroupId &&
2974+ tab . groupId != - 1 ) {
2975+ mixedTabs . push ( win . tabGroups . get ( tab . groupId ) ) ;
2976+ //console.log('Tab.getVirtualScrollRenderableTabs: inserted group item, ', mixedTabs[mixedTabs.length-1]);
2977+ }
2978+ mixedTabs . push ( tab ) ;
2979+ previousGroupId = tab . groupId ;
2980+ }
2981+ //console.log('Tab.getVirtualScrollRenderableTabs: ', mixedTabs);
2982+
2983+ return mixedTabs ;
29192984} ;
29202985
29212986Tab . getNeedToBeSynchronizedTabs = ( windowId = null , options = { } ) => {
@@ -2992,6 +3057,16 @@ Tab.getRecycledTabs = (windowId = null, options = {}) => {
29923057 } ) ;
29933058} ;
29943059
3060+ Tab . getNativeGroupMemberTabs = ( windowId = null , groupId , options = { } ) => {
3061+ return TabsStore . queryAll ( {
3062+ windowId,
3063+ tabs : TabsStore . getTabsMap ( TabsStore . nativelyGroupedTabsInWindow , windowId ) ,
3064+ living : true ,
3065+ groupId,
3066+ ...options
3067+ } ) ;
3068+ } ;
3069+
29953070
29963071//===================================================================
29973072// general tab events
0 commit comments