@@ -8,6 +8,7 @@ define(function (require, exports, module) {
88 const CommandManager = require ( "command/CommandManager" ) ;
99 const Commands = require ( "command/Commands" ) ;
1010 const DocumentManager = require ( "document/DocumentManager" ) ;
11+ const WorkspaceManager = require ( "view/WorkspaceManager" ) ;
1112
1213 const Global = require ( "./global" ) ;
1314 const Helper = require ( "./helper" ) ;
@@ -141,7 +142,7 @@ define(function (require, exports, module) {
141142 * Sets up the tab bar
142143 */
143144 function setupTabBar ( ) {
144- // this populates the working sets
145+ // this populates the working sets present in `global.js`
145146 getAllFilesFromWorkingSet ( ) ;
146147
147148 // if no files are present in a pane, we want to hide the tab bar for that pane
@@ -190,6 +191,7 @@ define(function (require, exports, module) {
190191 displayedEntries . forEach ( function ( entry ) {
191192 $firstTabBar . append ( createTab ( entry ) ) ;
192193 Overflow . toggleOverflowVisibility ( "first-pane" ) ;
194+ Overflow . scrollToActiveTab ( $firstTabBar ) ;
193195 } ) ;
194196 }
195197
@@ -207,6 +209,7 @@ define(function (require, exports, module) {
207209 displayedEntries2 . forEach ( function ( entry ) {
208210 $secondTabBar . append ( createTab ( entry ) ) ;
209211 Overflow . toggleOverflowVisibility ( "second-pane" ) ;
212+ Overflow . scrollToActiveTab ( $firstTabBar ) ;
210213 } ) ;
211214 }
212215 }
@@ -225,21 +228,129 @@ define(function (require, exports, module) {
225228
226229 if ( $ ( '.not-editor' ) . length === 1 ) {
227230 $tabBar = $ ( TabBarHTML ) ;
228- // since we need to add the tab bar before the editor area, we target the `.not-editor` class
229- $ ( ".not-editor" ) . before ( $tabBar ) ;
231+ // since we need to add the tab bar before the editor area, we target the `#editor-holder` class and prepend
232+ $ ( "#editor-holder" ) . prepend ( $tabBar ) ;
233+ setTimeout ( function ( ) {
234+ WorkspaceManager . recomputeLayout ( true ) ;
235+ } , 0 ) ;
236+
230237 } else if ( $ ( '.not-editor' ) . length === 2 ) {
231238 $tabBar = $ ( TabBarHTML ) ;
232239 $tabBar2 = $ ( TabBarHTML2 ) ;
233240
234241 // eq(0) is for the first pane and eq(1) is for the second pane
242+ // here #editor-holder cannot be used as in split view, we only have one #editor-holder
243+ // so, right now we are using .not-editor. Maybe we need to look for some better selector
244+ // TODO: Fix bug where the tab bar gets hidden inside the editor in horizontal split
235245 $ ( ".not-editor" ) . eq ( 0 ) . before ( $tabBar ) ;
236246 $ ( ".not-editor" ) . eq ( 1 ) . before ( $tabBar2 ) ;
247+ setTimeout ( function ( ) {
248+ WorkspaceManager . recomputeLayout ( true ) ;
249+ } , 0 ) ;
237250 }
238251
239252 setupTabBar ( ) ;
240253 }
241254
242255
256+ /**
257+ * This function updates the tabs in the tab bar
258+ * It is called when the working set changes. So instead of creating a new tab bar, we just update the existing one
259+ */
260+ function updateTabs ( ) {
261+ // Get all files from the working set. refer to `global.js`
262+ getAllFilesFromWorkingSet ( ) ;
263+
264+ // When there is only one file, we enforce the creation of the tab bar
265+ // this is done because, given the situation:
266+ // In a vertical split, when no files are present in 'second-pane' so the tab bar is hidden.
267+ // Now, when the user adds a file in 'second-pane', the tab bar should be shown but since updateTabs() only,
268+ // updates the tabs, so the tab bar never gets created.
269+ if ( Global . firstPaneWorkingSet . length === 1 || Global . secondPaneWorkingSet . length === 1 ) {
270+ createTabBar ( ) ;
271+ return ;
272+ }
273+
274+ const $firstTabBar = $ ( '#phoenix-tab-bar' ) ;
275+ // Update first pane's tabs
276+ if ( $firstTabBar . length ) {
277+ $firstTabBar . empty ( ) ;
278+ if ( Global . firstPaneWorkingSet . length > 0 ) {
279+
280+ // get the count of tabs that we want to display in the tab bar (from preference settings)
281+ // from preference settings or working set whichever smaller
282+ let tabsCountP1 = Math . min ( Global . firstPaneWorkingSet . length , Preference . tabBarNumberOfTabs ) ;
283+
284+ // the value is generally '-1', but we check for less than 0 so that it can handle edge cases gracefully
285+ // if the value is negative then we display all tabs
286+ if ( Preference . tabBarNumberOfTabs < 0 ) {
287+ tabsCountP1 = Global . firstPaneWorkingSet . length ;
288+ }
289+
290+ let displayedEntries = Global . firstPaneWorkingSet . slice ( 0 , tabsCountP1 ) ;
291+
292+ const activeEditor = EditorManager . getActiveEditor ( ) ;
293+ const activePath = activeEditor ? activeEditor . document . file . fullPath : null ;
294+ if ( activePath && ! displayedEntries . some ( entry => entry . path === activePath ) ) {
295+ let activeEntry = Global . firstPaneWorkingSet . find ( entry => entry . path === activePath ) ;
296+ if ( activeEntry ) {
297+ displayedEntries [ displayedEntries . length - 1 ] = activeEntry ;
298+ }
299+ }
300+ displayedEntries . forEach ( function ( entry ) {
301+ $firstTabBar . append ( createTab ( entry ) ) ;
302+ } ) ;
303+ }
304+ }
305+
306+ const $secondTabBar = $ ( '#phoenix-tab-bar-2' ) ;
307+ // Update second pane's tabs
308+ if ( $secondTabBar . length ) {
309+ $secondTabBar . empty ( ) ;
310+ if ( Global . secondPaneWorkingSet . length > 0 ) {
311+
312+ let tabsCountP2 = Math . min ( Global . secondPaneWorkingSet . length , Preference . tabBarNumberOfTabs ) ;
313+ if ( Preference . tabBarNumberOfTabs < 0 ) {
314+ tabsCountP2 = Global . secondPaneWorkingSet . length ;
315+ }
316+
317+ let displayedEntries2 = Global . secondPaneWorkingSet . slice ( 0 , tabsCountP2 ) ;
318+ const activeEditor = EditorManager . getActiveEditor ( ) ;
319+ const activePath = activeEditor ? activeEditor . document . file . fullPath : null ;
320+ if ( activePath && ! displayedEntries2 . some ( entry => entry . path === activePath ) ) {
321+ let activeEntry = Global . secondPaneWorkingSet . find ( entry => entry . path === activePath ) ;
322+ if ( activeEntry ) {
323+ displayedEntries2 [ displayedEntries2 . length - 1 ] = activeEntry ;
324+ }
325+ }
326+ displayedEntries2 . forEach ( function ( entry ) {
327+ $secondTabBar . append ( createTab ( entry ) ) ;
328+ } ) ;
329+ }
330+ }
331+
332+ // if no files are present in a pane, we want to hide the tab bar for that pane
333+ if ( Global . firstPaneWorkingSet . length === 0 && ( $ ( '#phoenix-tab-bar' ) ) ) {
334+ Helper . _hideTabBar ( $ ( '#phoenix-tab-bar' ) , $ ( '#overflow-button' ) ) ;
335+ }
336+
337+ if ( Global . secondPaneWorkingSet . length === 0 && ( $ ( '#phoenix-tab-bar-2' ) ) ) {
338+ Helper . _hideTabBar ( $ ( '#phoenix-tab-bar-2' ) , $ ( '#overflow-button-2' ) ) ;
339+ }
340+
341+ // Now that tabs are updated, scroll to the active tab if necessary.
342+ if ( $firstTabBar . length ) {
343+ Overflow . toggleOverflowVisibility ( "first-pane" ) ;
344+ Overflow . scrollToActiveTab ( $firstTabBar ) ;
345+ }
346+
347+ if ( $secondTabBar . length ) {
348+ Overflow . toggleOverflowVisibility ( "second-pane" ) ;
349+ Overflow . scrollToActiveTab ( $secondTabBar ) ;
350+ }
351+ }
352+
353+
243354 /**
244355 * Removes existing tab bar and cleans up
245356 */
@@ -358,29 +469,25 @@ define(function (require, exports, module) {
358469 * Registers the event handlers
359470 */
360471 function registerHandlers ( ) {
361-
362- // pane handlers
472+ // For pane changes, still recreate the entire tab bar container.
363473 MainViewManager . off ( "activePaneChange paneCreate paneDestroy paneLayoutChange" , createTabBar ) ;
364474 MainViewManager . on ( "activePaneChange paneCreate paneDestroy paneLayoutChange" , createTabBar ) ;
365475
366- // editor handlers
367- EditorManager . off ( "activeEditorChange" , createTabBar ) ;
368- EditorManager . on ( "activeEditorChange" , createTabBar ) ;
369-
370- // when working set changes, recreate the tab bar
371- // we listen to all of these events to ensure that the tab bar is always up to date
372- // refer to `MainViewManager.js` for more details
373- MainViewManager . on ( "workingSetAdd" , createTabBar ) ;
374- MainViewManager . on ( "workingSetRemove" , createTabBar ) ;
375- MainViewManager . on ( "workingSetSort" , createTabBar ) ;
376- MainViewManager . on ( "workingSetMove" , createTabBar ) ;
377- MainViewManager . on ( "workingSetAddList" , createTabBar ) ;
378- MainViewManager . on ( "workingSetRemoveList" , createTabBar ) ;
379- MainViewManager . on ( "workingSetUpdate" , createTabBar ) ;
380- MainViewManager . on ( "_workingSetDisableAutoSort" , createTabBar ) ;
381-
382-
383- // file dirty flag change handler
476+ // For editor changes, update only the tabs.
477+ EditorManager . off ( "activeEditorChange" , updateTabs ) ;
478+ EditorManager . on ( "activeEditorChange" , updateTabs ) ;
479+
480+ // For working set changes, update only the tabs.
481+ MainViewManager . on ( "workingSetAdd" , updateTabs ) ;
482+ MainViewManager . on ( "workingSetRemove" , updateTabs ) ;
483+ MainViewManager . on ( "workingSetSort" , updateTabs ) ;
484+ MainViewManager . on ( "workingSetMove" , updateTabs ) ;
485+ MainViewManager . on ( "workingSetAddList" , updateTabs ) ;
486+ MainViewManager . on ( "workingSetRemoveList" , updateTabs ) ;
487+ MainViewManager . on ( "workingSetUpdate" , updateTabs ) ;
488+ MainViewManager . on ( "_workingSetDisableAutoSort" , updateTabs ) ;
489+
490+ // file dirty flag change remains unchanged.
384491 DocumentManager . on ( "dirtyFlagChange" , function ( event , doc ) {
385492 const filePath = doc . file . fullPath ;
386493
0 commit comments