diff --git a/spec/pane-container-spec.js b/spec/pane-container-spec.js index a21c3fd9c0e..d96f759b151 100644 --- a/spec/pane-container-spec.js +++ b/spec/pane-container-spec.js @@ -391,7 +391,7 @@ describe('PaneContainer', () => { }); }); - describe('::onWillDestroyPaneItem() and ::onDidDestroyPaneItem', () => { + describe('::onWillDestroyPaneItem() and ::onDidDestroyPaneItem()', () => { it('invokes the given callbacks when an item will be destroyed on any pane', async () => { const container = new PaneContainer(params); const pane1 = container.getRoot(); @@ -409,14 +409,37 @@ describe('PaneContainer', () => { await pane2.destroyItem(item3); await pane2.destroyItem(item2); - expect(events).toEqual([ - ['will', { item: item1, pane: pane1, index: 0 }], - ['did', { item: item1, pane: pane1, index: 0 }], - ['will', { item: item3, pane: pane2, index: 1 }], - ['did', { item: item3, pane: pane2, index: 1 }], - ['will', { item: item2, pane: pane2, index: 0 }], - ['did', { item: item2, pane: pane2, index: 0 }] + expect(events.length).toBe(6); + expect(events[1]).toEqual([ + 'did', + { item: item1, pane: pane1, index: 0 } + ]); + expect(events[3]).toEqual([ + 'did', + { item: item3, pane: pane2, index: 1 } ]); + expect(events[5]).toEqual([ + 'did', + { item: item2, pane: pane2, index: 0 } + ]); + + expect(events[0][0]).toEqual('will'); + expect(events[0][1].item).toEqual(item1); + expect(events[0][1].pane).toEqual(pane1); + expect(events[0][1].index).toEqual(0); + expect(typeof events[0][1].prevent).toEqual('function'); + + expect(events[2][0]).toEqual('will'); + expect(events[2][1].item).toEqual(item3); + expect(events[2][1].pane).toEqual(pane2); + expect(events[2][1].index).toEqual(1); + expect(typeof events[2][1].prevent).toEqual('function'); + + expect(events[4][0]).toEqual('will'); + expect(events[4][1].item).toEqual(item2); + expect(events[4][1].pane).toEqual(pane2); + expect(events[4][1].index).toEqual(0); + expect(typeof events[4][1].prevent).toEqual('function'); }); }); diff --git a/spec/pane-spec.js b/spec/pane-spec.js index 873e9f8fc18..7482f9662de 100644 --- a/spec/pane-spec.js +++ b/spec/pane-spec.js @@ -568,6 +568,32 @@ describe('Pane', () => { expect(pane.getActiveItem()).toBeUndefined(); }); + it('does nothing if prevented', () => { + const container = new PaneContainer({ + config: atom.config, + deserializerManager: atom.deserializers, + applicationDelegate: atom.applicationDelegate + }); + + pane.setContainer(container); + container.onWillDestroyPaneItem(e => e.prevent()); + pane.itemStack = [item2, item3, item1]; + + pane.activateItem(item1); + expect(pane.getActiveItem()).toBe(item1); + pane.destroyItem(item3); + expect(pane.itemStack).toEqual([item2, item3, item1]); + expect(pane.getActiveItem()).toBe(item1); + + pane.destroyItem(item1); + expect(pane.itemStack).toEqual([item2, item3, item1]); + expect(pane.getActiveItem()).toBe(item1); + + pane.destroyItem(item2); + expect(pane.itemStack).toEqual([item2, item3, item1]); + expect(pane.getActiveItem()).toBe(item1); + }); + it('invokes ::onWillDestroyItem() and PaneContainer::onWillDestroyPaneItem observers before destroying the item', async () => { jasmine.useRealClock(); pane.container = new PaneContainer({ config: atom.config, confirm }); @@ -589,10 +615,16 @@ describe('Pane', () => { await pane.destroyItem(item2); expect(item2.isDestroyed()).toBe(true); - expect(events).toEqual([ - ['will-destroy-item', { item: item2, index: 1 }], - ['will-destroy-pane-item', { item: item2, index: 1, pane }] - ]); + + expect(events[0][0]).toEqual('will-destroy-item'); + expect(events[0][1].item).toEqual(item2); + expect(events[0][1].index).toEqual(1); + + expect(events[1][0]).toEqual('will-destroy-pane-item'); + expect(events[1][1].item).toEqual(item2); + expect(events[1][1].index).toEqual(1); + expect(typeof events[1][1].prevent).toEqual('function'); + expect(events[1][1].pane).toEqual(pane); }); it('invokes ::onWillRemoveItem() observers', () => { diff --git a/src/pane.js b/src/pane.js index 4b4f4a6f35e..a55575ae049 100644 --- a/src/pane.js +++ b/src/pane.js @@ -814,6 +814,9 @@ module.exports = class Pane { // last item, the pane will be destroyed if the `core.destroyEmptyPanes` config // setting is `true`. // + // This action can be prevented by onWillDestroyPaneItem callbacks in which + // case nothing happens. + // // * `item` Item to destroy // * `force` (optional) {Boolean} Destroy the item without prompting to save // it, even if the item's `isPermanentDockItem` method returns true. @@ -844,7 +847,16 @@ module.exports = class Pane { 'will-destroy-pane-item' ) > 0 ) { - await this.container.willDestroyPaneItem({ item, index, pane: this }); + let preventClosing = false; + await this.container.willDestroyPaneItem({ + item, + index, + pane: this, + prevent: () => { + preventClosing = true; + } + }); + if (preventClosing) return false; } if (