@@ -139,6 +139,43 @@ define(function (require, exports, module) {
139139 } ) ;
140140 }
141141
142+ /**
143+ * Append a single tab to the tab bar for the given panel.
144+ * Use instead of _updateBottomPanelTabBar() when adding one tab.
145+ * @param {string } panelId
146+ * @private
147+ */
148+ function _addTabToBar ( panelId ) {
149+ if ( ! _$tabsOverflow ) {
150+ return ;
151+ }
152+ let panel = _panelMap [ panelId ] ;
153+ if ( ! panel ) {
154+ return ;
155+ }
156+ let title = panel . _tabTitle || _getPanelTitle ( panelId , panel . $panel ) ;
157+ let isActive = ( panelId === _activeId ) ;
158+ let $tab = $ ( '<div class="bottom-panel-tab"></div>' )
159+ . toggleClass ( 'active' , isActive )
160+ . attr ( 'data-panel-id' , panelId ) ;
161+ $tab . append ( $ ( '<span class="bottom-panel-tab-title"></span>' ) . text ( title ) ) ;
162+ $tab . append ( $ ( '<span class="bottom-panel-tab-close-btn">×</span>' ) . attr ( 'title' , Strings . CLOSE ) ) ;
163+ _$tabsOverflow . append ( $tab ) ;
164+ }
165+
166+ /**
167+ * Remove a single tab from the tab bar by panel ID.
168+ * Use instead of _updateBottomPanelTabBar() when removing one tab.
169+ * @param {string } panelId
170+ * @private
171+ */
172+ function _removeTabFromBar ( panelId ) {
173+ if ( ! _$tabsOverflow ) {
174+ return ;
175+ }
176+ _$tabsOverflow . find ( '.bottom-panel-tab[data-panel-id="' + panelId + '"]' ) . remove ( ) ;
177+ }
178+
142179 /**
143180 * Switch the active tab to the given panel. Does not show/hide the container.
144181 * @param {string } panelId
@@ -223,7 +260,7 @@ define(function (require, exports, module) {
223260 * Shows the panel
224261 */
225262 Panel . prototype . show = function ( ) {
226- if ( ! this . canBeShown ( ) ) {
263+ if ( ! this . canBeShown ( ) || ! _$container ) {
227264 return ;
228265 }
229266 let panelId = this . panelID ;
@@ -256,7 +293,7 @@ define(function (require, exports, module) {
256293 }
257294
258295 _switchToTab ( panelId ) ;
259- _updateBottomPanelTabBar ( ) ;
296+ _addTabToBar ( panelId ) ;
260297 exports . trigger ( EVENT_PANEL_SHOWN , panelId ) ;
261298 } ;
262299
@@ -276,22 +313,30 @@ define(function (require, exports, module) {
276313 this . $panel . removeClass ( "active-bottom-panel" ) ;
277314
278315 let wasActive = ( _activeId === panelId ) ;
316+ let activatedId = null ;
279317
280- // Tab was removed — rebuild tab bar, then activate next if needed
281318 if ( wasActive && _openIds . length > 0 ) {
282319 let nextIdx = Math . min ( idx , _openIds . length - 1 ) ;
283- let nextId = _openIds [ nextIdx ] ;
320+ activatedId = _openIds [ nextIdx ] ;
284321 _activeId = null ; // clear so _switchToTab runs
285- _switchToTab ( nextId ) ;
286- exports . trigger ( EVENT_PANEL_SHOWN , nextId ) ;
322+ _switchToTab ( activatedId ) ;
287323 } else if ( wasActive ) {
288324 // No more tabs - hide the container
289325 _activeId = null ;
290- Resizer . hide ( _$container [ 0 ] ) ;
326+ if ( _$container ) {
327+ Resizer . hide ( _$container [ 0 ] ) ;
328+ }
291329 }
292- _updateBottomPanelTabBar ( ) ;
293330
331+ _removeTabFromBar ( panelId ) ;
332+
333+ // Always fire HIDDEN for the closed panel first
294334 exports . trigger ( EVENT_PANEL_HIDDEN , panelId ) ;
335+
336+ // Then fire SHOWN for the newly activated tab, if any
337+ if ( activatedId ) {
338+ exports . trigger ( EVENT_PANEL_SHOWN , activatedId ) ;
339+ }
295340 } ;
296341
297342 /**
@@ -318,6 +363,18 @@ define(function (require, exports, module) {
318363 }
319364 } ;
320365
366+ /**
367+ * Destroys the panel, removing it from the tab bar, internal maps, and the DOM.
368+ * After calling this, the Panel instance should not be reused.
369+ */
370+ Panel . prototype . destroy = function ( ) {
371+ if ( _openIds . indexOf ( this . panelID ) !== - 1 ) {
372+ this . hide ( ) ;
373+ }
374+ delete _panelMap [ this . panelID ] ;
375+ this . $panel . remove ( ) ;
376+ } ;
377+
321378 /**
322379 * gets the Panel's type
323380 * @return {string }
0 commit comments