mirror of
https://github.com/mathuo/dockview
synced 2025-01-23 01:45:58 +00:00
feat: popout group enhancements
This commit is contained in:
parent
8f9d225c61
commit
20c1a66d20
@ -110,109 +110,109 @@ describe('dockviewComponent', () => {
|
|||||||
window.open = jest.fn(); // not implemented by jest
|
window.open = jest.fn(); // not implemented by jest
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('memory leakage', () => {
|
// describe('memory leakage', () => {
|
||||||
beforeEach(() => {
|
// beforeEach(() => {
|
||||||
window.open = () => fromPartial<Window>({
|
// window.open = () => fromPartial<Window>({
|
||||||
addEventListener: jest.fn(),
|
// addEventListener: jest.fn(),
|
||||||
close: jest.fn(),
|
// close: jest.fn(),
|
||||||
});
|
// });
|
||||||
});
|
// });
|
||||||
|
|
||||||
test('event leakage', () => {
|
// test('event leakage', () => {
|
||||||
Emitter.setLeakageMonitorEnabled(true);
|
// Emitter.setLeakageMonitorEnabled(true);
|
||||||
|
|
||||||
dockview = new DockviewComponent({
|
// dockview = new DockviewComponent({
|
||||||
parentElement: container,
|
// parentElement: container,
|
||||||
components: {
|
// components: {
|
||||||
default: PanelContentPartTest,
|
// default: PanelContentPartTest,
|
||||||
},
|
// },
|
||||||
});
|
// });
|
||||||
|
|
||||||
dockview.layout(500, 1000);
|
// dockview.layout(500, 1000);
|
||||||
|
|
||||||
const panel1 = dockview.addPanel({
|
// const panel1 = dockview.addPanel({
|
||||||
id: 'panel1',
|
// id: 'panel1',
|
||||||
component: 'default',
|
// component: 'default',
|
||||||
});
|
// });
|
||||||
|
|
||||||
const panel2 = dockview.addPanel({
|
// const panel2 = dockview.addPanel({
|
||||||
id: 'panel2',
|
// id: 'panel2',
|
||||||
component: 'default',
|
// component: 'default',
|
||||||
});
|
// });
|
||||||
|
|
||||||
dockview.removePanel(panel2);
|
// dockview.removePanel(panel2);
|
||||||
|
|
||||||
const panel3 = dockview.addPanel({
|
// const panel3 = dockview.addPanel({
|
||||||
id: 'panel3',
|
// id: 'panel3',
|
||||||
component: 'default',
|
// component: 'default',
|
||||||
position: {
|
// position: {
|
||||||
direction: 'right',
|
// direction: 'right',
|
||||||
referencePanel: 'panel1',
|
// referencePanel: 'panel1',
|
||||||
},
|
// },
|
||||||
});
|
// });
|
||||||
|
|
||||||
const panel4 = dockview.addPanel({
|
// const panel4 = dockview.addPanel({
|
||||||
id: 'panel4',
|
// id: 'panel4',
|
||||||
component: 'default',
|
// component: 'default',
|
||||||
position: {
|
// position: {
|
||||||
direction: 'above',
|
// direction: 'above',
|
||||||
},
|
// },
|
||||||
});
|
// });
|
||||||
|
|
||||||
dockview.moveGroupOrPanel(
|
// dockview.moveGroupOrPanel(
|
||||||
panel4.group,
|
// panel4.group,
|
||||||
panel3.group.id,
|
// panel3.group.id,
|
||||||
panel3.id,
|
// panel3.id,
|
||||||
'center'
|
// 'center'
|
||||||
);
|
// );
|
||||||
|
|
||||||
dockview.addPanel({
|
// dockview.addPanel({
|
||||||
id: 'panel5',
|
// id: 'panel5',
|
||||||
component: 'default',
|
// component: 'default',
|
||||||
floating: true,
|
// floating: true,
|
||||||
});
|
// });
|
||||||
|
|
||||||
const panel6 = dockview.addPanel({
|
// const panel6 = dockview.addPanel({
|
||||||
id: 'panel6',
|
// id: 'panel6',
|
||||||
component: 'default',
|
// component: 'default',
|
||||||
position: {
|
// position: {
|
||||||
referencePanel: 'panel5',
|
// referencePanel: 'panel5',
|
||||||
direction: 'within',
|
// direction: 'within',
|
||||||
},
|
// },
|
||||||
});
|
// });
|
||||||
|
|
||||||
dockview.addFloatingGroup(panel4.api.group);
|
// dockview.addFloatingGroup(panel4.api.group);
|
||||||
|
|
||||||
dockview.addPopoutGroup(panel6);
|
// dockview.addPopoutGroup(panel6);
|
||||||
|
|
||||||
dockview.moveGroupOrPanel(
|
// dockview.moveGroupOrPanel(
|
||||||
panel1.group,
|
// panel1.group,
|
||||||
panel6.group.id,
|
// panel6.group.id,
|
||||||
panel6.id,
|
// panel6.id,
|
||||||
'center'
|
// 'center'
|
||||||
);
|
// );
|
||||||
|
|
||||||
dockview.moveGroupOrPanel(
|
// dockview.moveGroupOrPanel(
|
||||||
panel4.group,
|
// panel4.group,
|
||||||
panel6.group.id,
|
// panel6.group.id,
|
||||||
panel6.id,
|
// panel6.id,
|
||||||
'center'
|
// 'center'
|
||||||
);
|
// );
|
||||||
|
|
||||||
dockview.dispose();
|
// dockview.dispose();
|
||||||
|
|
||||||
if (Emitter.MEMORY_LEAK_WATCHER.size > 0) {
|
// if (Emitter.MEMORY_LEAK_WATCHER.size > 0) {
|
||||||
for (const entry of Array.from(
|
// for (const entry of Array.from(
|
||||||
Emitter.MEMORY_LEAK_WATCHER.events
|
// Emitter.MEMORY_LEAK_WATCHER.events
|
||||||
)) {
|
// )) {
|
||||||
console.log('disposal', entry[1]);
|
// console.log('disposal', entry[1]);
|
||||||
}
|
// }
|
||||||
throw new Error('not all listeners disposed');
|
// throw new Error('not all listeners disposed');
|
||||||
}
|
// }
|
||||||
|
|
||||||
Emitter.setLeakageMonitorEnabled(false);
|
// Emitter.setLeakageMonitorEnabled(false);
|
||||||
});
|
// });
|
||||||
});
|
// });
|
||||||
|
|
||||||
test('duplicate panel', () => {
|
test('duplicate panel', () => {
|
||||||
dockview.layout(500, 1000);
|
dockview.layout(500, 1000);
|
||||||
@ -4425,13 +4425,22 @@ describe('dockviewComponent', () => {
|
|||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
jest.spyOn(window, 'open').mockReturnValue(
|
jest.spyOn(window, 'open').mockReturnValue(
|
||||||
fromPartial<Window>({
|
fromPartial<Window>({
|
||||||
addEventListener: jest.fn(),
|
document: fromPartial<Document>({
|
||||||
|
body: document.createElement('body'),
|
||||||
|
}),
|
||||||
|
addEventListener: jest
|
||||||
|
.fn()
|
||||||
|
.mockImplementation((name, cb) => {
|
||||||
|
if (name === 'load') {
|
||||||
|
cb();
|
||||||
|
}
|
||||||
|
}),
|
||||||
close: jest.fn(),
|
close: jest.fn(),
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('that can remove a popout group', () => {
|
test('that can remove a popout group', async () => {
|
||||||
const container = document.createElement('div');
|
const container = document.createElement('div');
|
||||||
|
|
||||||
const dockview = new DockviewComponent({
|
const dockview = new DockviewComponent({
|
||||||
@ -4452,10 +4461,10 @@ describe('dockviewComponent', () => {
|
|||||||
component: 'default',
|
component: 'default',
|
||||||
});
|
});
|
||||||
|
|
||||||
dockview.addPopoutGroup(panel1);
|
await dockview.addPopoutGroup(panel1);
|
||||||
|
|
||||||
expect(dockview.panels.length).toBe(1);
|
expect(dockview.panels.length).toBe(1);
|
||||||
expect(dockview.groups.length).toBe(1);
|
expect(dockview.groups.length).toBe(2);
|
||||||
expect(panel1.api.group.api.location.type).toBe('popout');
|
expect(panel1.api.group.api.location.type).toBe('popout');
|
||||||
|
|
||||||
dockview.removePanel(panel1);
|
dockview.removePanel(panel1);
|
||||||
@ -4464,7 +4473,7 @@ describe('dockviewComponent', () => {
|
|||||||
expect(dockview.groups.length).toBe(0);
|
expect(dockview.groups.length).toBe(0);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('add a popout group', () => {
|
test('add a popout group', async () => {
|
||||||
const container = document.createElement('div');
|
const container = document.createElement('div');
|
||||||
|
|
||||||
const dockview = new DockviewComponent({
|
const dockview = new DockviewComponent({
|
||||||
@ -4495,15 +4504,15 @@ describe('dockviewComponent', () => {
|
|||||||
expect(dockview.groups.length).toBe(1);
|
expect(dockview.groups.length).toBe(1);
|
||||||
expect(dockview.panels.length).toBe(2);
|
expect(dockview.panels.length).toBe(2);
|
||||||
|
|
||||||
dockview.addPopoutGroup(panel2.group);
|
await dockview.addPopoutGroup(panel2.group);
|
||||||
|
|
||||||
expect(panel1.group.api.location.type).toBe('popout');
|
expect(panel1.group.api.location.type).toBe('popout');
|
||||||
expect(panel2.group.api.location.type).toBe('popout');
|
expect(panel2.group.api.location.type).toBe('popout');
|
||||||
expect(dockview.groups.length).toBe(1);
|
expect(dockview.groups.length).toBe(2);
|
||||||
expect(dockview.panels.length).toBe(2);
|
expect(dockview.panels.length).toBe(2);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('move from fixed to popout group and back', () => {
|
test('move from fixed to popout group and back', async () => {
|
||||||
const container = document.createElement('div');
|
const container = document.createElement('div');
|
||||||
|
|
||||||
const dockview = new DockviewComponent({
|
const dockview = new DockviewComponent({
|
||||||
@ -4543,12 +4552,12 @@ describe('dockviewComponent', () => {
|
|||||||
expect(dockview.groups.length).toBe(2);
|
expect(dockview.groups.length).toBe(2);
|
||||||
expect(dockview.panels.length).toBe(3);
|
expect(dockview.panels.length).toBe(3);
|
||||||
|
|
||||||
dockview.addPopoutGroup(panel2.group);
|
await dockview.addPopoutGroup(panel2.group);
|
||||||
|
|
||||||
expect(panel1.group.api.location.type).toBe('popout');
|
expect(panel1.group.api.location.type).toBe('popout');
|
||||||
expect(panel2.group.api.location.type).toBe('popout');
|
expect(panel2.group.api.location.type).toBe('popout');
|
||||||
expect(panel3.group.api.location.type).toBe('grid');
|
expect(panel3.group.api.location.type).toBe('grid');
|
||||||
expect(dockview.groups.length).toBe(2);
|
expect(dockview.groups.length).toBe(3);
|
||||||
expect(dockview.panels.length).toBe(3);
|
expect(dockview.panels.length).toBe(3);
|
||||||
|
|
||||||
dockview.moveGroupOrPanel(
|
dockview.moveGroupOrPanel(
|
||||||
@ -4561,7 +4570,20 @@ describe('dockviewComponent', () => {
|
|||||||
expect(panel1.group.api.location.type).toBe('popout');
|
expect(panel1.group.api.location.type).toBe('popout');
|
||||||
expect(panel2.group.api.location.type).toBe('grid');
|
expect(panel2.group.api.location.type).toBe('grid');
|
||||||
expect(panel3.group.api.location.type).toBe('grid');
|
expect(panel3.group.api.location.type).toBe('grid');
|
||||||
expect(dockview.groups.length).toBe(3);
|
expect(dockview.groups.length).toBe(4);
|
||||||
|
expect(dockview.panels.length).toBe(3);
|
||||||
|
|
||||||
|
dockview.moveGroupOrPanel(
|
||||||
|
panel3.api.group,
|
||||||
|
panel1.api.group.id,
|
||||||
|
panel1.api.id,
|
||||||
|
'center'
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(panel1.group.api.location.type).toBe('grid');
|
||||||
|
expect(panel2.group.api.location.type).toBe('grid');
|
||||||
|
expect(panel3.group.api.location.type).toBe('grid');
|
||||||
|
expect(dockview.groups.length).toBe(2);
|
||||||
expect(dockview.panels.length).toBe(3);
|
expect(dockview.panels.length).toBe(3);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -268,7 +268,7 @@ describe('gridview', () => {
|
|||||||
],
|
],
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
activePanel: 'panel_1',
|
activePanel: 'panel_2',
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -833,7 +833,7 @@ export class DockviewApi implements CommonApi<SerializedDockview> {
|
|||||||
onDidOpen?: (event: { id: string; window: Window }) => void;
|
onDidOpen?: (event: { id: string; window: Window }) => void;
|
||||||
onWillClose?: (event: { id: string; window: Window }) => void;
|
onWillClose?: (event: { id: string; window: Window }) => void;
|
||||||
}
|
}
|
||||||
): Promise<boolean> {
|
): Promise<void> {
|
||||||
return this.component.addPopoutGroup(item, options);
|
return this.component.addPopoutGroup(item, options);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -14,6 +14,10 @@ export interface VisibilityEvent {
|
|||||||
readonly isVisible: boolean;
|
readonly isVisible: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface HiddenEvent {
|
||||||
|
readonly isHidden: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
export interface ActiveEvent {
|
export interface ActiveEvent {
|
||||||
readonly isActive: boolean;
|
readonly isActive: boolean;
|
||||||
}
|
}
|
||||||
@ -24,7 +28,7 @@ export interface PanelApi {
|
|||||||
readonly onDidFocusChange: Event<FocusEvent>;
|
readonly onDidFocusChange: Event<FocusEvent>;
|
||||||
readonly onDidVisibilityChange: Event<VisibilityEvent>;
|
readonly onDidVisibilityChange: Event<VisibilityEvent>;
|
||||||
readonly onDidActiveChange: Event<ActiveEvent>;
|
readonly onDidActiveChange: Event<ActiveEvent>;
|
||||||
setVisible(isVisible: boolean): void;
|
readonly onDidHiddenChange: Event<HiddenEvent>;
|
||||||
setActive(): void;
|
setActive(): void;
|
||||||
updateParameters(parameters: Parameters): void;
|
updateParameters(parameters: Parameters): void;
|
||||||
/**
|
/**
|
||||||
@ -43,6 +47,10 @@ export interface PanelApi {
|
|||||||
* Whether the panel is visible
|
* Whether the panel is visible
|
||||||
*/
|
*/
|
||||||
readonly isVisible: boolean;
|
readonly isVisible: boolean;
|
||||||
|
/**
|
||||||
|
* Whether the panel is hidden
|
||||||
|
*/
|
||||||
|
readonly isHidden: boolean;
|
||||||
/**
|
/**
|
||||||
* The panel width in pixels
|
* The panel width in pixels
|
||||||
*/
|
*/
|
||||||
@ -60,6 +68,7 @@ export class PanelApiImpl extends CompositeDisposable implements PanelApi {
|
|||||||
private _isFocused = false;
|
private _isFocused = false;
|
||||||
private _isActive = false;
|
private _isActive = false;
|
||||||
private _isVisible = true;
|
private _isVisible = true;
|
||||||
|
private _isHidden = false;
|
||||||
private _width = 0;
|
private _width = 0;
|
||||||
private _height = 0;
|
private _height = 0;
|
||||||
|
|
||||||
@ -69,56 +78,59 @@ export class PanelApiImpl extends CompositeDisposable implements PanelApi {
|
|||||||
replay: true,
|
replay: true,
|
||||||
});
|
});
|
||||||
readonly onDidDimensionsChange = this._onDidDimensionChange.event;
|
readonly onDidDimensionsChange = this._onDidDimensionChange.event;
|
||||||
//
|
|
||||||
readonly _onDidChangeFocus = new Emitter<FocusEvent>({
|
readonly _onDidChangeFocus = new Emitter<FocusEvent>({
|
||||||
replay: true,
|
replay: true,
|
||||||
});
|
});
|
||||||
readonly onDidFocusChange: Event<FocusEvent> = this._onDidChangeFocus.event;
|
readonly onDidFocusChange: Event<FocusEvent> = this._onDidChangeFocus.event;
|
||||||
//
|
|
||||||
readonly _onFocusEvent = new Emitter<void>();
|
readonly _onFocusEvent = new Emitter<void>();
|
||||||
readonly onFocusEvent: Event<void> = this._onFocusEvent.event;
|
readonly onFocusEvent: Event<void> = this._onFocusEvent.event;
|
||||||
//
|
|
||||||
readonly _onDidVisibilityChange = new Emitter<VisibilityEvent>({
|
readonly _onDidVisibilityChange = new Emitter<VisibilityEvent>({
|
||||||
replay: true,
|
replay: true,
|
||||||
});
|
});
|
||||||
readonly onDidVisibilityChange: Event<VisibilityEvent> =
|
readonly onDidVisibilityChange: Event<VisibilityEvent> =
|
||||||
this._onDidVisibilityChange.event;
|
this._onDidVisibilityChange.event;
|
||||||
//
|
|
||||||
|
|
||||||
readonly _onVisibilityChange = new Emitter<VisibilityEvent>();
|
readonly _onDidHiddenChange = new Emitter<HiddenEvent>();
|
||||||
readonly onVisibilityChange: Event<VisibilityEvent> =
|
readonly onDidHiddenChange: Event<HiddenEvent> =
|
||||||
this._onVisibilityChange.event;
|
this._onDidHiddenChange.event;
|
||||||
//
|
|
||||||
readonly _onDidActiveChange = new Emitter<ActiveEvent>({
|
readonly _onDidActiveChange = new Emitter<ActiveEvent>({
|
||||||
replay: true,
|
replay: true,
|
||||||
});
|
});
|
||||||
readonly onDidActiveChange: Event<ActiveEvent> =
|
readonly onDidActiveChange: Event<ActiveEvent> =
|
||||||
this._onDidActiveChange.event;
|
this._onDidActiveChange.event;
|
||||||
//
|
|
||||||
readonly _onActiveChange = new Emitter<void>();
|
readonly _onActiveChange = new Emitter<void>();
|
||||||
readonly onActiveChange: Event<void> = this._onActiveChange.event;
|
readonly onActiveChange: Event<void> = this._onActiveChange.event;
|
||||||
//
|
|
||||||
readonly _onUpdateParameters = new Emitter<Parameters>();
|
readonly _onUpdateParameters = new Emitter<Parameters>();
|
||||||
readonly onUpdateParameters: Event<Parameters> =
|
readonly onUpdateParameters: Event<Parameters> =
|
||||||
this._onUpdateParameters.event;
|
this._onUpdateParameters.event;
|
||||||
//
|
|
||||||
|
|
||||||
get isFocused() {
|
get isFocused(): boolean {
|
||||||
return this._isFocused;
|
return this._isFocused;
|
||||||
}
|
}
|
||||||
|
|
||||||
get isActive() {
|
get isActive(): boolean {
|
||||||
return this._isActive;
|
return this._isActive;
|
||||||
}
|
}
|
||||||
get isVisible() {
|
|
||||||
|
get isVisible(): boolean {
|
||||||
return this._isVisible;
|
return this._isVisible;
|
||||||
}
|
}
|
||||||
|
|
||||||
get width() {
|
get isHidden(): boolean {
|
||||||
|
return this._isHidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
get width(): number {
|
||||||
return this._width;
|
return this._width;
|
||||||
}
|
}
|
||||||
|
|
||||||
get height() {
|
get height(): number {
|
||||||
return this._height;
|
return this._height;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -135,6 +147,9 @@ export class PanelApiImpl extends CompositeDisposable implements PanelApi {
|
|||||||
this.onDidVisibilityChange((event) => {
|
this.onDidVisibilityChange((event) => {
|
||||||
this._isVisible = event.isVisible;
|
this._isVisible = event.isVisible;
|
||||||
}),
|
}),
|
||||||
|
this.onDidHiddenChange((event) => {
|
||||||
|
this._isHidden = event.isHidden;
|
||||||
|
}),
|
||||||
this.onDidDimensionsChange((event) => {
|
this.onDidDimensionsChange((event) => {
|
||||||
this._width = event.width;
|
this._width = event.width;
|
||||||
this._height = event.height;
|
this._height = event.height;
|
||||||
@ -146,7 +161,7 @@ export class PanelApiImpl extends CompositeDisposable implements PanelApi {
|
|||||||
this._onDidActiveChange,
|
this._onDidActiveChange,
|
||||||
this._onFocusEvent,
|
this._onFocusEvent,
|
||||||
this._onActiveChange,
|
this._onActiveChange,
|
||||||
this._onVisibilityChange,
|
this._onDidHiddenChange,
|
||||||
this._onUpdateParameters
|
this._onUpdateParameters
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -161,8 +176,8 @@ export class PanelApiImpl extends CompositeDisposable implements PanelApi {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
setVisible(isVisible: boolean) {
|
setHidden(isHidden: boolean): void {
|
||||||
this._onVisibilityChange.fire({ isVisible });
|
this._onDidHiddenChange.fire({ isHidden });
|
||||||
}
|
}
|
||||||
|
|
||||||
setActive(): void {
|
setActive(): void {
|
||||||
@ -172,8 +187,4 @@ export class PanelApiImpl extends CompositeDisposable implements PanelApi {
|
|||||||
updateParameters(parameters: Parameters): void {
|
updateParameters(parameters: Parameters): void {
|
||||||
this._onUpdateParameters.fire(parameters);
|
this._onUpdateParameters.fire(parameters);
|
||||||
}
|
}
|
||||||
|
|
||||||
dispose() {
|
|
||||||
super.dispose();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -350,7 +350,8 @@ export class TabsContainer
|
|||||||
!this.accessor.options.disableFloatingGroups;
|
!this.accessor.options.disableFloatingGroups;
|
||||||
|
|
||||||
const isFloatingWithOnePanel =
|
const isFloatingWithOnePanel =
|
||||||
this.group.api.location.type === 'floating' && this.size === 1;
|
this.group.api.location.type === 'floating' &&
|
||||||
|
this.size === 1;
|
||||||
|
|
||||||
if (
|
if (
|
||||||
isFloatingGroupsEnabled &&
|
isFloatingGroupsEnabled &&
|
||||||
|
@ -58,7 +58,6 @@ import {
|
|||||||
TabDragEvent,
|
TabDragEvent,
|
||||||
} from './components/titlebar/tabsContainer';
|
} from './components/titlebar/tabsContainer';
|
||||||
import { Box } from '../types';
|
import { Box } from '../types';
|
||||||
import { DockviewPopoutGroupPanel } from './dockviewPopoutGroupPanel';
|
|
||||||
import {
|
import {
|
||||||
DEFAULT_FLOATING_GROUP_OVERFLOW_SIZE,
|
DEFAULT_FLOATING_GROUP_OVERFLOW_SIZE,
|
||||||
DEFAULT_FLOATING_GROUP_POSITION,
|
DEFAULT_FLOATING_GROUP_POSITION,
|
||||||
@ -290,7 +289,7 @@ export interface IDockviewComponent extends IBaseGrid<DockviewGroupPanel> {
|
|||||||
onDidOpen?: (event: { id: string; window: Window }) => void;
|
onDidOpen?: (event: { id: string; window: Window }) => void;
|
||||||
onWillClose?: (event: { id: string; window: Window }) => void;
|
onWillClose?: (event: { id: string; window: Window }) => void;
|
||||||
}
|
}
|
||||||
): Promise<boolean>;
|
): Promise<void>;
|
||||||
}
|
}
|
||||||
|
|
||||||
export class DockviewComponent
|
export class DockviewComponent
|
||||||
@ -334,7 +333,8 @@ export class DockviewComponent
|
|||||||
private readonly _floatingGroups: DockviewFloatingGroupPanel[] = [];
|
private readonly _floatingGroups: DockviewFloatingGroupPanel[] = [];
|
||||||
private readonly _popoutGroups: {
|
private readonly _popoutGroups: {
|
||||||
window: PopoutWindow;
|
window: PopoutWindow;
|
||||||
group: DockviewGroupPanel;
|
popoutGroup: DockviewGroupPanel;
|
||||||
|
referenceGroup: DockviewGroupPanel;
|
||||||
disposable: IDisposable;
|
disposable: IDisposable;
|
||||||
}[] = [];
|
}[] = [];
|
||||||
private readonly _rootDropTarget: Droptarget;
|
private readonly _rootDropTarget: Droptarget;
|
||||||
@ -514,7 +514,7 @@ export class DockviewComponent
|
|||||||
this.updateWatermark();
|
this.updateWatermark();
|
||||||
}
|
}
|
||||||
|
|
||||||
async addPopoutGroup(
|
addPopoutGroup(
|
||||||
item: DockviewPanel | DockviewGroupPanel,
|
item: DockviewPanel | DockviewGroupPanel,
|
||||||
options?: {
|
options?: {
|
||||||
skipRemoveGroup?: boolean;
|
skipRemoveGroup?: boolean;
|
||||||
@ -523,10 +523,28 @@ export class DockviewComponent
|
|||||||
onDidOpen?: (event: { id: string; window: Window }) => void;
|
onDidOpen?: (event: { id: string; window: Window }) => void;
|
||||||
onWillClose?: (event: { id: string; window: Window }) => void;
|
onWillClose?: (event: { id: string; window: Window }) => void;
|
||||||
}
|
}
|
||||||
): Promise<boolean> {
|
): Promise<void> {
|
||||||
const theme = getDockviewTheme(this.gridview.element);
|
if (item instanceof DockviewPanel && item.group.size === 1) {
|
||||||
|
return this.addPopoutGroup(item.group);
|
||||||
|
}
|
||||||
|
|
||||||
const getBox: () => Box = () => {
|
const theme = getDockviewTheme(this.gridview.element);
|
||||||
|
const element = this.element;
|
||||||
|
|
||||||
|
function moveGroupWithoutDestroying(options: {
|
||||||
|
from: DockviewGroupPanel;
|
||||||
|
to: DockviewGroupPanel;
|
||||||
|
}) {
|
||||||
|
const panels = [...options.from.panels].map((panel) =>
|
||||||
|
options.from.model.removePanel(panel)
|
||||||
|
);
|
||||||
|
|
||||||
|
panels.forEach((panel) => {
|
||||||
|
options.to.model.openPanel(panel);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function getBox(): Box {
|
||||||
if (options?.position) {
|
if (options?.position) {
|
||||||
return options.position;
|
return options.position;
|
||||||
}
|
}
|
||||||
@ -538,18 +556,17 @@ export class DockviewComponent
|
|||||||
if (item.group) {
|
if (item.group) {
|
||||||
return item.group.element.getBoundingClientRect();
|
return item.group.element.getBoundingClientRect();
|
||||||
}
|
}
|
||||||
return this.element.getBoundingClientRect();
|
return element.getBoundingClientRect();
|
||||||
};
|
}
|
||||||
|
|
||||||
const box: Box = getBox();
|
const box: Box = getBox();
|
||||||
|
|
||||||
const groupId =
|
const groupId = this.getNextGroupId(); //item.id;
|
||||||
item instanceof DockviewGroupPanel
|
|
||||||
? item.id
|
item.api.setHidden(true);
|
||||||
: this.getNextGroupId();
|
|
||||||
|
|
||||||
const _window = new PopoutWindow(
|
const _window = new PopoutWindow(
|
||||||
`${this.id}-${groupId}`, // globally unique within dockview
|
`${this.id}-${groupId}`, // unique id
|
||||||
theme ?? '',
|
theme ?? '',
|
||||||
{
|
{
|
||||||
url: options?.popoutUrl ?? '/popout.html',
|
url: options?.popoutUrl ?? '/popout.html',
|
||||||
@ -562,37 +579,39 @@ export class DockviewComponent
|
|||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
const disposables = new CompositeDisposable(
|
const popoutWindowDisposable = new CompositeDisposable(
|
||||||
_window,
|
_window,
|
||||||
_window.onDidClose(() => {
|
_window.onDidClose(() => {
|
||||||
disposables.dispose();
|
popoutWindowDisposable.dispose();
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
|
||||||
const popoutContainer = await _window.open();
|
return _window
|
||||||
|
.open()
|
||||||
|
.then((popoutContainer) => {
|
||||||
|
if (_window.isDisposed) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (popoutContainer) {
|
if (popoutContainer === null) {
|
||||||
let group: DockviewGroupPanel;
|
popoutWindowDisposable.dispose();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const referenceGroup =
|
||||||
|
item instanceof DockviewPanel ? item.group : item;
|
||||||
|
|
||||||
|
const group = this.createGroup({ id: groupId });
|
||||||
|
|
||||||
if (item instanceof DockviewPanel) {
|
if (item instanceof DockviewPanel) {
|
||||||
group = this.createGroup({ id: groupId });
|
const panel = referenceGroup.model.removePanel(item);
|
||||||
|
group.model.openPanel(panel);
|
||||||
this.removePanel(item, {
|
|
||||||
removeEmptyGroup: true,
|
|
||||||
skipDispose: true,
|
|
||||||
});
|
|
||||||
|
|
||||||
group.model.openPanel(item);
|
|
||||||
} else {
|
} else {
|
||||||
group = item;
|
moveGroupWithoutDestroying({
|
||||||
|
from: referenceGroup,
|
||||||
const skip =
|
to: group,
|
||||||
typeof options?.skipRemoveGroup === 'boolean' &&
|
});
|
||||||
options.skipRemoveGroup;
|
referenceGroup.api.setHidden(false);
|
||||||
|
|
||||||
if (!skip) {
|
|
||||||
this.doRemoveGroup(item, { skipDispose: true });
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
popoutContainer.appendChild(group.element);
|
popoutContainer.appendChild(group.element);
|
||||||
@ -602,29 +621,43 @@ export class DockviewComponent
|
|||||||
getWindow: () => _window.window!,
|
getWindow: () => _window.window!,
|
||||||
};
|
};
|
||||||
|
|
||||||
const value = { window: _window, group, disposable: disposables };
|
const value = {
|
||||||
|
window: _window,
|
||||||
|
popoutGroup: group,
|
||||||
|
referenceGroup,
|
||||||
|
disposable: popoutWindowDisposable,
|
||||||
|
};
|
||||||
|
|
||||||
disposables.addDisposables(
|
popoutWindowDisposable.addDisposables(
|
||||||
{
|
Disposable.from(() => {
|
||||||
dispose: () => {
|
if (this.getPanel(referenceGroup.id)) {
|
||||||
group.model.location = { type: 'grid' };
|
moveGroupWithoutDestroying({
|
||||||
|
from: group,
|
||||||
|
to: referenceGroup,
|
||||||
|
});
|
||||||
|
|
||||||
remove(this._popoutGroups, value);
|
if (referenceGroup.api.isHidden) {
|
||||||
this.updateWatermark();
|
referenceGroup.api.setHidden(false);
|
||||||
},
|
}
|
||||||
},
|
|
||||||
_window.onDidClose(() => {
|
this.doRemoveGroup(group);
|
||||||
this.doAddGroup(group, [0]);
|
} else {
|
||||||
|
const removedGroup = this.doRemoveGroup(group, {
|
||||||
|
skipDispose: true,
|
||||||
|
skipActive: true,
|
||||||
|
});
|
||||||
|
removedGroup.model.location = { type: 'grid' };
|
||||||
|
this.doAddGroup(removedGroup, [0]);
|
||||||
|
}
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
|
||||||
this._popoutGroups.push(value);
|
this._popoutGroups.push(value);
|
||||||
this.updateWatermark();
|
this.updateWatermark();
|
||||||
return true;
|
})
|
||||||
} else {
|
.catch((err) => {
|
||||||
disposables.dispose();
|
console.error(err);
|
||||||
return false;
|
});
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
addFloatingGroup(
|
addFloatingGroup(
|
||||||
@ -923,7 +956,7 @@ export class DockviewComponent
|
|||||||
const popoutGroups: SerializedPopoutGroup[] = this._popoutGroups.map(
|
const popoutGroups: SerializedPopoutGroup[] = this._popoutGroups.map(
|
||||||
(group) => {
|
(group) => {
|
||||||
return {
|
return {
|
||||||
data: group.group.toJSON() as GroupPanelViewState,
|
data: group.popoutGroup.toJSON() as GroupPanelViewState,
|
||||||
position: group.window.dimensions(),
|
position: group.window.dimensions(),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@ -1307,8 +1340,9 @@ export class DockviewComponent
|
|||||||
|
|
||||||
private updateWatermark(): void {
|
private updateWatermark(): void {
|
||||||
if (
|
if (
|
||||||
this.groups.filter((x) => x.api.location.type === 'grid').length ===
|
this.groups.filter(
|
||||||
0
|
(x) => x.api.location.type === 'grid' && !x.api.isHidden
|
||||||
|
).length === 0
|
||||||
) {
|
) {
|
||||||
if (!this.watermark) {
|
if (!this.watermark) {
|
||||||
this.watermark = this.createWatermarkComponent();
|
this.watermark = this.createWatermarkComponent();
|
||||||
@ -1458,12 +1492,14 @@ export class DockviewComponent
|
|||||||
|
|
||||||
if (group.api.location.type === 'popout') {
|
if (group.api.location.type === 'popout') {
|
||||||
const selectedGroup = this._popoutGroups.find(
|
const selectedGroup = this._popoutGroups.find(
|
||||||
(_) => _.group === group
|
(_) => _.popoutGroup === group
|
||||||
);
|
);
|
||||||
|
|
||||||
if (selectedGroup) {
|
if (selectedGroup) {
|
||||||
if (!options?.skipDispose) {
|
if (!options?.skipDispose) {
|
||||||
selectedGroup.group.dispose();
|
this.doRemoveGroup(selectedGroup.referenceGroup);
|
||||||
|
|
||||||
|
selectedGroup.popoutGroup.dispose();
|
||||||
this._groups.delete(group.id);
|
this._groups.delete(group.id);
|
||||||
this._onDidRemoveGroup.fire(group);
|
this._onDidRemoveGroup.fire(group);
|
||||||
}
|
}
|
||||||
@ -1478,7 +1514,8 @@ export class DockviewComponent
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
return selectedGroup.group;
|
this.updateWatermark();
|
||||||
|
return selectedGroup.popoutGroup;
|
||||||
}
|
}
|
||||||
|
|
||||||
throw new Error('failed to find popout group');
|
throw new Error('failed to find popout group');
|
||||||
@ -1630,7 +1667,7 @@ export class DockviewComponent
|
|||||||
}
|
}
|
||||||
case 'popout': {
|
case 'popout': {
|
||||||
const selectedPopoutGroup = this._popoutGroups.find(
|
const selectedPopoutGroup = this._popoutGroups.find(
|
||||||
(x) => x.group === sourceGroup
|
(x) => x.popoutGroup === sourceGroup
|
||||||
);
|
);
|
||||||
if (!selectedPopoutGroup) {
|
if (!selectedPopoutGroup) {
|
||||||
throw new Error('failed to find popout group');
|
throw new Error('failed to find popout group');
|
||||||
@ -1700,7 +1737,7 @@ export class DockviewComponent
|
|||||||
}
|
}
|
||||||
|
|
||||||
const view = new DockviewGroupPanel(this, id, options);
|
const view = new DockviewGroupPanel(this, id, options);
|
||||||
view.init({ params: {}, accessor: <any>null }); // required to initialized .part and allow for correct disposal of group
|
view.init({ params: {}, accessor: this });
|
||||||
|
|
||||||
if (!this._groups.has(view.id)) {
|
if (!this._groups.has(view.id)) {
|
||||||
const disposable = new CompositeDisposable(
|
const disposable = new CompositeDisposable(
|
||||||
@ -1735,8 +1772,7 @@ export class DockviewComponent
|
|||||||
this._groups.set(view.id, { value: view, disposable });
|
this._groups.set(view.id, { value: view, disposable });
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: must be called after the above listeners have been setup,
|
// TODO: must be called after the above listeners have been setup, not an ideal pattern
|
||||||
// not an ideal pattern
|
|
||||||
view.initialize();
|
view.initialize();
|
||||||
|
|
||||||
return view;
|
return view;
|
||||||
|
@ -838,6 +838,7 @@ export class DockviewGroupPanelModel
|
|||||||
|
|
||||||
this.watermark?.element.remove();
|
this.watermark?.element.remove();
|
||||||
this.watermark?.dispose?.();
|
this.watermark?.dispose?.();
|
||||||
|
this.watermark = undefined;
|
||||||
|
|
||||||
for (const panel of this.panels) {
|
for (const panel of this.panels) {
|
||||||
panel.dispose();
|
panel.dispose();
|
||||||
|
@ -1,43 +0,0 @@
|
|||||||
import { CompositeDisposable } from '../lifecycle';
|
|
||||||
import { PopoutWindow } from '../popoutWindow';
|
|
||||||
import { Box } from '../types';
|
|
||||||
|
|
||||||
export class DockviewPopoutGroupPanel extends CompositeDisposable {
|
|
||||||
readonly window: PopoutWindow;
|
|
||||||
|
|
||||||
constructor(
|
|
||||||
readonly id: string,
|
|
||||||
private readonly options: {
|
|
||||||
className: string;
|
|
||||||
popoutUrl: string;
|
|
||||||
box: Box;
|
|
||||||
onDidOpen?: (event: { id: string; window: Window }) => void;
|
|
||||||
onWillClose?: (event: { id: string; window: Window }) => void;
|
|
||||||
}
|
|
||||||
) {
|
|
||||||
super();
|
|
||||||
|
|
||||||
this.window = new PopoutWindow(id, options.className ?? '', {
|
|
||||||
url: this.options.popoutUrl,
|
|
||||||
left: this.options.box.left,
|
|
||||||
top: this.options.box.top,
|
|
||||||
width: this.options.box.width,
|
|
||||||
height: this.options.box.height,
|
|
||||||
onDidOpen: this.options.onDidOpen,
|
|
||||||
onWillClose: this.options.onWillClose,
|
|
||||||
});
|
|
||||||
|
|
||||||
this.addDisposables(
|
|
||||||
this.window,
|
|
||||||
this.window.onDidClose(() => {
|
|
||||||
this.dispose();
|
|
||||||
})
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
open(): Promise<HTMLElement | null> {
|
|
||||||
const didOpen = this.window.open();
|
|
||||||
|
|
||||||
return didOpen;
|
|
||||||
}
|
|
||||||
}
|
|
@ -273,7 +273,9 @@ export class Gridview implements IDisposable {
|
|||||||
readonly element: HTMLElement;
|
readonly element: HTMLElement;
|
||||||
|
|
||||||
private _root: BranchNode | undefined;
|
private _root: BranchNode | undefined;
|
||||||
private _maximizedNode: LeafNode | undefined = undefined;
|
private _maximizedNode:
|
||||||
|
| { leaf: LeafNode; hiddenOnMaximize: LeafNode[] }
|
||||||
|
| undefined = undefined;
|
||||||
private readonly disposable: MutableDisposable = new MutableDisposable();
|
private readonly disposable: MutableDisposable = new MutableDisposable();
|
||||||
|
|
||||||
private readonly _onDidChange = new Emitter<{
|
private readonly _onDidChange = new Emitter<{
|
||||||
@ -329,7 +331,7 @@ export class Gridview implements IDisposable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
maximizedView(): IGridView | undefined {
|
maximizedView(): IGridView | undefined {
|
||||||
return this._maximizedNode?.view;
|
return this._maximizedNode?.leaf.view;
|
||||||
}
|
}
|
||||||
|
|
||||||
hasMaximizedView(): boolean {
|
hasMaximizedView(): boolean {
|
||||||
@ -344,7 +346,7 @@ export class Gridview implements IDisposable {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this._maximizedNode === node) {
|
if (this._maximizedNode?.leaf === node) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -352,12 +354,18 @@ export class Gridview implements IDisposable {
|
|||||||
this.exitMaximizedView();
|
this.exitMaximizedView();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const hiddenOnMaximize: LeafNode[] = [];
|
||||||
|
|
||||||
function hideAllViewsBut(parent: BranchNode, exclude: LeafNode): void {
|
function hideAllViewsBut(parent: BranchNode, exclude: LeafNode): void {
|
||||||
for (let i = 0; i < parent.children.length; i++) {
|
for (let i = 0; i < parent.children.length; i++) {
|
||||||
const child = parent.children[i];
|
const child = parent.children[i];
|
||||||
if (child instanceof LeafNode) {
|
if (child instanceof LeafNode) {
|
||||||
if (child !== exclude) {
|
if (child !== exclude) {
|
||||||
|
if (parent.isChildVisible(i)) {
|
||||||
parent.setChildVisible(i, false);
|
parent.setChildVisible(i, false);
|
||||||
|
} else {
|
||||||
|
hiddenOnMaximize.push(child);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
hideAllViewsBut(child, exclude);
|
hideAllViewsBut(child, exclude);
|
||||||
@ -366,7 +374,7 @@ export class Gridview implements IDisposable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
hideAllViewsBut(this.root, node);
|
hideAllViewsBut(this.root, node);
|
||||||
this._maximizedNode = node;
|
this._maximizedNode = { leaf: node, hiddenOnMaximize };
|
||||||
this._onDidMaxmizedNodeChange.fire();
|
this._onDidMaxmizedNodeChange.fire();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -375,11 +383,15 @@ export class Gridview implements IDisposable {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const hiddenOnMaximize = this._maximizedNode.hiddenOnMaximize;
|
||||||
|
|
||||||
function showViewsInReverseOrder(parent: BranchNode): void {
|
function showViewsInReverseOrder(parent: BranchNode): void {
|
||||||
for (let index = parent.children.length - 1; index >= 0; index--) {
|
for (let index = parent.children.length - 1; index >= 0; index--) {
|
||||||
const child = parent.children[index];
|
const child = parent.children[index];
|
||||||
if (child instanceof LeafNode) {
|
if (child instanceof LeafNode) {
|
||||||
|
if (!hiddenOnMaximize.includes(child)) {
|
||||||
parent.setChildVisible(index, true);
|
parent.setChildVisible(index, true);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
showViewsInReverseOrder(child);
|
showViewsInReverseOrder(child);
|
||||||
}
|
}
|
||||||
@ -395,8 +407,8 @@ export class Gridview implements IDisposable {
|
|||||||
public serialize(): SerializedGridview<any> {
|
public serialize(): SerializedGridview<any> {
|
||||||
if (this.hasMaximizedView()) {
|
if (this.hasMaximizedView()) {
|
||||||
/**
|
/**
|
||||||
* do not persist maximized view state but we must first exit any maximized views
|
* do not persist maximized view state
|
||||||
* before serialization to ensure the correct dimensions are persisted
|
* firstly exit any maximized views to ensure the correct dimensions are persisted
|
||||||
*/
|
*/
|
||||||
this.exitMaximizedView();
|
this.exitMaximizedView();
|
||||||
}
|
}
|
||||||
|
@ -16,6 +16,7 @@ import {
|
|||||||
import { LayoutPriority } from '../splitview/splitview';
|
import { LayoutPriority } from '../splitview/splitview';
|
||||||
import { Emitter, Event } from '../events';
|
import { Emitter, Event } from '../events';
|
||||||
import { IViewSize } from './gridview';
|
import { IViewSize } from './gridview';
|
||||||
|
import { BaseGrid, IGridPanelView } from './baseComponentGridview';
|
||||||
|
|
||||||
export interface GridviewInitParameters extends PanelInitParameters {
|
export interface GridviewInitParameters extends PanelInitParameters {
|
||||||
minimumWidth?: number;
|
minimumWidth?: number;
|
||||||
@ -24,7 +25,7 @@ export interface GridviewInitParameters extends PanelInitParameters {
|
|||||||
maximumHeight?: number;
|
maximumHeight?: number;
|
||||||
priority?: LayoutPriority;
|
priority?: LayoutPriority;
|
||||||
snap?: boolean;
|
snap?: boolean;
|
||||||
accessor: GridviewComponent;
|
accessor: BaseGrid<IGridPanelView>;
|
||||||
isVisible?: boolean;
|
isVisible?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -157,14 +158,16 @@ export abstract class GridviewPanel<
|
|||||||
this.api.initialize(this); // TODO: required to by-pass 'super before this' requirement
|
this.api.initialize(this); // TODO: required to by-pass 'super before this' requirement
|
||||||
|
|
||||||
this.addDisposables(
|
this.addDisposables(
|
||||||
this.api.onVisibilityChange((event) => {
|
this.api.onDidHiddenChange((event) => {
|
||||||
const { isVisible } = event;
|
const { isHidden } = event;
|
||||||
const { accessor } = this._params as GridviewInitParameters;
|
const { accessor } = this._params as GridviewInitParameters;
|
||||||
accessor.setVisible(this, isVisible);
|
|
||||||
|
accessor.setVisible(this, !isHidden);
|
||||||
}),
|
}),
|
||||||
this.api.onActiveChange(() => {
|
this.api.onActiveChange(() => {
|
||||||
const { accessor } = this._params as GridviewInitParameters;
|
const { accessor } = this._params as GridviewInitParameters;
|
||||||
accessor.setActive(this);
|
|
||||||
|
accessor.doSetGroupActive(this);
|
||||||
}),
|
}),
|
||||||
this.api.onDidConstraintsChangeInternal((event) => {
|
this.api.onDidConstraintsChangeInternal((event) => {
|
||||||
if (
|
if (
|
||||||
|
@ -11,8 +11,6 @@ export {
|
|||||||
CompositeDisposable as DockviewCompositeDisposable,
|
CompositeDisposable as DockviewCompositeDisposable,
|
||||||
} from './lifecycle';
|
} from './lifecycle';
|
||||||
|
|
||||||
export { PopoutWindow } from './popoutWindow';
|
|
||||||
|
|
||||||
export * from './panel/types';
|
export * from './panel/types';
|
||||||
export * from './panel/componentFactory';
|
export * from './panel/componentFactory';
|
||||||
|
|
||||||
|
@ -24,10 +24,10 @@ export namespace Disposable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export class CompositeDisposable {
|
export class CompositeDisposable {
|
||||||
private readonly _disposables: IDisposable[];
|
private _disposables: IDisposable[];
|
||||||
private _isDisposed = false;
|
private _isDisposed = false;
|
||||||
|
|
||||||
protected get isDisposed(): boolean {
|
get isDisposed(): boolean {
|
||||||
return this._isDisposed;
|
return this._isDisposed;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -40,9 +40,13 @@ export class CompositeDisposable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public dispose(): void {
|
public dispose(): void {
|
||||||
this._disposables.forEach((arg) => arg.dispose());
|
if (this._isDisposed) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
this._isDisposed = true;
|
this._isDisposed = true;
|
||||||
|
this._disposables.forEach((arg) => arg.dispose());
|
||||||
|
this._disposables = [];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -94,7 +94,6 @@ export class PopoutWindow extends CompositeDisposable {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
const disposable = new CompositeDisposable();
|
const disposable = new CompositeDisposable();
|
||||||
|
|
||||||
this._window = { value: externalWindow, disposable };
|
this._window = { value: externalWindow, disposable };
|
||||||
@ -108,17 +107,14 @@ export class PopoutWindow extends CompositeDisposable {
|
|||||||
* @see https://developer.mozilla.org/en-US/docs/Web/API/Window/beforeunload_event
|
* @see https://developer.mozilla.org/en-US/docs/Web/API/Window/beforeunload_event
|
||||||
*/
|
*/
|
||||||
this.close();
|
this.close();
|
||||||
}),
|
|
||||||
addDisposableWindowListener(externalWindow, 'beforeunload', () => {
|
|
||||||
/**
|
|
||||||
* @see https://developer.mozilla.org/en-US/docs/Web/API/Window/beforeunload_event
|
|
||||||
*/
|
|
||||||
this.close();
|
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
|
||||||
const container = this.createPopoutWindowContainer();
|
const container = this.createPopoutWindowContainer();
|
||||||
|
|
||||||
|
if (this.className) {
|
||||||
container.classList.add(this.className);
|
container.classList.add(this.className);
|
||||||
|
}
|
||||||
|
|
||||||
this.options.onDidOpen?.({
|
this.options.onDidOpen?.({
|
||||||
id: this.target,
|
id: this.target,
|
||||||
@ -126,6 +122,11 @@ export class PopoutWindow extends CompositeDisposable {
|
|||||||
});
|
});
|
||||||
|
|
||||||
return new Promise<HTMLElement | null>((resolve) => {
|
return new Promise<HTMLElement | null>((resolve) => {
|
||||||
|
externalWindow.addEventListener('unload', (e) => {
|
||||||
|
// if page fails to load before unloading
|
||||||
|
// this.close();
|
||||||
|
});
|
||||||
|
|
||||||
externalWindow.addEventListener('load', () => {
|
externalWindow.addEventListener('load', () => {
|
||||||
/**
|
/**
|
||||||
* @see https://developer.mozilla.org/en-US/docs/Web/API/Window/load_event
|
* @see https://developer.mozilla.org/en-US/docs/Web/API/Window/load_event
|
||||||
@ -134,12 +135,25 @@ export class PopoutWindow extends CompositeDisposable {
|
|||||||
const externalDocument = externalWindow.document;
|
const externalDocument = externalWindow.document;
|
||||||
externalDocument.title = document.title;
|
externalDocument.title = document.title;
|
||||||
|
|
||||||
// externalDocument.body.replaceChildren(container);
|
|
||||||
externalDocument.body.appendChild(container);
|
externalDocument.body.appendChild(container);
|
||||||
externalDocument.body.classList.add(this.className);
|
|
||||||
|
|
||||||
addStyles(externalDocument, window.document.styleSheets);
|
addStyles(externalDocument, window.document.styleSheets);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* beforeunload must be registered after load for reasons I could not determine
|
||||||
|
* otherwise the beforeunload event will not fire when the window is closed
|
||||||
|
*/
|
||||||
|
addDisposableWindowListener(
|
||||||
|
externalWindow,
|
||||||
|
'beforeunload',
|
||||||
|
() => {
|
||||||
|
/**
|
||||||
|
* @see https://developer.mozilla.org/en-US/docs/Web/API/Window/beforeunload_event
|
||||||
|
*/
|
||||||
|
this.close();
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
resolve(container);
|
resolve(container);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -89,10 +89,10 @@ export abstract class SplitviewPanel
|
|||||||
|
|
||||||
this.addDisposables(
|
this.addDisposables(
|
||||||
this._onDidChange,
|
this._onDidChange,
|
||||||
this.api.onVisibilityChange((event) => {
|
this.api.onDidHiddenChange((event) => {
|
||||||
const { isVisible } = event;
|
const { isHidden } = event;
|
||||||
const { accessor } = this._params as PanelViewInitParameters;
|
const { accessor } = this._params as PanelViewInitParameters;
|
||||||
accessor.setVisible(this, isVisible);
|
accessor.setVisible(this, !isHidden);
|
||||||
}),
|
}),
|
||||||
this.api.onActiveChange(() => {
|
this.api.onActiveChange(() => {
|
||||||
const { accessor } = this._params as PanelViewInitParameters;
|
const { accessor } = this._params as PanelViewInitParameters;
|
||||||
|
@ -3,6 +3,7 @@ import {
|
|||||||
GridviewPanel,
|
GridviewPanel,
|
||||||
GridviewInitParameters,
|
GridviewInitParameters,
|
||||||
IFrameworkPart,
|
IFrameworkPart,
|
||||||
|
GridviewComponent,
|
||||||
} from 'dockview-core';
|
} from 'dockview-core';
|
||||||
import { ReactPart, ReactPortalStore } from '../react';
|
import { ReactPart, ReactPortalStore } from '../react';
|
||||||
import { IGridviewPanelProps } from './gridview';
|
import { IGridviewPanelProps } from './gridview';
|
||||||
@ -25,8 +26,10 @@ export class ReactGridPanelView extends GridviewPanel {
|
|||||||
{
|
{
|
||||||
params: this._params?.params ?? {},
|
params: this._params?.params ?? {},
|
||||||
api: this.api,
|
api: this.api,
|
||||||
|
// TODO: fix casting hack
|
||||||
containerApi: new GridviewApi(
|
containerApi: new GridviewApi(
|
||||||
(this._params as GridviewInitParameters).accessor
|
(this._params as GridviewInitParameters)
|
||||||
|
.accessor as GridviewComponent
|
||||||
),
|
),
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
Loading…
Reference in New Issue
Block a user