mirror of
https://github.com/mathuo/dockview
synced 2025-05-04 10:38:24 +00:00
feat: Improve onDidAdd/onDidRemove events for pane/splitview
This commit is contained in:
parent
6ba8015502
commit
67b4b2502f
105
packages/dockview/src/__tests__/paneview/paneview.spec.ts
Normal file
105
packages/dockview/src/__tests__/paneview/paneview.spec.ts
Normal file
@ -0,0 +1,105 @@
|
|||||||
|
import { CompositeDisposable } from '../../lifecycle';
|
||||||
|
import { Paneview } from '../../paneview/paneview';
|
||||||
|
import {
|
||||||
|
IPaneBodyPart,
|
||||||
|
IPaneHeaderPart,
|
||||||
|
PaneviewPanel,
|
||||||
|
} from '../../paneview/paneviewPanel';
|
||||||
|
import { Orientation } from '../../splitview/core/splitview';
|
||||||
|
|
||||||
|
class TestPanel extends PaneviewPanel {
|
||||||
|
protected getBodyComponent(): IPaneBodyPart {
|
||||||
|
return {
|
||||||
|
element: document.createElement('div'),
|
||||||
|
update: () => {
|
||||||
|
//
|
||||||
|
},
|
||||||
|
dispose: () => {
|
||||||
|
//
|
||||||
|
},
|
||||||
|
init: () => {
|
||||||
|
// /
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
protected getHeaderComponent(): IPaneHeaderPart {
|
||||||
|
return {
|
||||||
|
element: document.createElement('div'),
|
||||||
|
update: () => {
|
||||||
|
//
|
||||||
|
},
|
||||||
|
dispose: () => {
|
||||||
|
//
|
||||||
|
},
|
||||||
|
init: () => {
|
||||||
|
// /
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
describe('paneview', () => {
|
||||||
|
let container: HTMLElement;
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
container = document.createElement('div');
|
||||||
|
container.className = 'container';
|
||||||
|
});
|
||||||
|
|
||||||
|
test('onDidAddView and onDidRemoveView events', () => {
|
||||||
|
const paneview = new Paneview(container, {
|
||||||
|
orientation: Orientation.HORIZONTAL,
|
||||||
|
});
|
||||||
|
|
||||||
|
const added: PaneviewPanel[] = [];
|
||||||
|
const removed: PaneviewPanel[] = [];
|
||||||
|
|
||||||
|
const disposable = new CompositeDisposable(
|
||||||
|
paneview.onDidAddView((view) => added.push(view)),
|
||||||
|
paneview.onDidRemoveView((view) => removed.push(view))
|
||||||
|
);
|
||||||
|
|
||||||
|
const view1 = new TestPanel(
|
||||||
|
'id',
|
||||||
|
'component',
|
||||||
|
'headerComponent',
|
||||||
|
Orientation.VERTICAL,
|
||||||
|
true,
|
||||||
|
true
|
||||||
|
);
|
||||||
|
const view2 = new TestPanel(
|
||||||
|
'id2',
|
||||||
|
'component',
|
||||||
|
'headerComponent',
|
||||||
|
Orientation.VERTICAL,
|
||||||
|
true,
|
||||||
|
true
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(added.length).toBe(0);
|
||||||
|
expect(removed.length).toBe(0);
|
||||||
|
|
||||||
|
paneview.addPane(view1);
|
||||||
|
expect(added.length).toBe(1);
|
||||||
|
expect(removed.length).toBe(0);
|
||||||
|
expect(added[0]).toBe(view1);
|
||||||
|
|
||||||
|
paneview.addPane(view2);
|
||||||
|
expect(added.length).toBe(2);
|
||||||
|
expect(removed.length).toBe(0);
|
||||||
|
expect(added[1]).toBe(view2);
|
||||||
|
|
||||||
|
paneview.removePane(0);
|
||||||
|
expect(added.length).toBe(2);
|
||||||
|
expect(removed.length).toBe(1);
|
||||||
|
expect(removed[0]).toBe(view1);
|
||||||
|
|
||||||
|
paneview.removePane(0);
|
||||||
|
expect(added.length).toBe(2);
|
||||||
|
expect(removed.length).toBe(2);
|
||||||
|
expect(removed[1]).toBe(view2);
|
||||||
|
|
||||||
|
disposable.dispose();
|
||||||
|
});
|
||||||
|
});
|
@ -12,7 +12,7 @@ import { Orientation } from '../../splitview/core/splitview';
|
|||||||
|
|
||||||
class TestPanel extends PaneviewPanel {
|
class TestPanel extends PaneviewPanel {
|
||||||
constructor(id: string, component: string) {
|
constructor(id: string, component: string) {
|
||||||
super(id, component, 'header', Orientation.VERTICAL, false);
|
super(id, component, 'header', Orientation.VERTICAL, false, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
getHeaderComponent() {
|
getHeaderComponent() {
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
import { last } from '../../../array';
|
import { last } from '../../../array';
|
||||||
import { Emitter } from '../../../events';
|
import { Emitter } from '../../../events';
|
||||||
|
import { CompositeDisposable } from '../../../lifecycle';
|
||||||
import {
|
import {
|
||||||
IView,
|
IView,
|
||||||
LayoutPriority,
|
LayoutPriority,
|
||||||
@ -522,4 +523,47 @@ describe('splitview', () => {
|
|||||||
]).toEqual([80, 100, 120]);
|
]).toEqual([80, 100, 120]);
|
||||||
expect(splitview.size).toBe(300);
|
expect(splitview.size).toBe(300);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('onDidAddView and onDidRemoveView events', () => {
|
||||||
|
const splitview = new Splitview(container, {
|
||||||
|
orientation: Orientation.HORIZONTAL,
|
||||||
|
proportionalLayout: false,
|
||||||
|
});
|
||||||
|
|
||||||
|
const added: IView[] = [];
|
||||||
|
const removed: IView[] = [];
|
||||||
|
|
||||||
|
const disposable = new CompositeDisposable(
|
||||||
|
splitview.onDidAddView((view) => added.push(view)),
|
||||||
|
splitview.onDidRemoveView((view) => removed.push(view))
|
||||||
|
);
|
||||||
|
|
||||||
|
const view1 = new Testview(0, 100);
|
||||||
|
const view2 = new Testview(0, 100);
|
||||||
|
|
||||||
|
expect(added.length).toBe(0);
|
||||||
|
expect(removed.length).toBe(0);
|
||||||
|
|
||||||
|
splitview.addView(view1);
|
||||||
|
expect(added.length).toBe(1);
|
||||||
|
expect(removed.length).toBe(0);
|
||||||
|
expect(added[0]).toBe(view1);
|
||||||
|
|
||||||
|
splitview.addView(view2);
|
||||||
|
expect(added.length).toBe(2);
|
||||||
|
expect(removed.length).toBe(0);
|
||||||
|
expect(added[1]).toBe(view2);
|
||||||
|
|
||||||
|
splitview.removeView(0);
|
||||||
|
expect(added.length).toBe(2);
|
||||||
|
expect(removed.length).toBe(1);
|
||||||
|
expect(removed[0]).toBe(view1);
|
||||||
|
|
||||||
|
splitview.removeView(0);
|
||||||
|
expect(added.length).toBe(2);
|
||||||
|
expect(removed.length).toBe(2);
|
||||||
|
expect(removed[1]).toBe(view2);
|
||||||
|
|
||||||
|
disposable.dispose();
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
@ -27,7 +27,7 @@ import {
|
|||||||
SerializedSplitview,
|
SerializedSplitview,
|
||||||
SplitviewComponentUpdateOptions,
|
SplitviewComponentUpdateOptions,
|
||||||
} from '../splitview/splitviewComponent';
|
} from '../splitview/splitviewComponent';
|
||||||
import { Orientation, Sizing } from '../splitview/core/splitview';
|
import { IView, Orientation, Sizing } from '../splitview/core/splitview';
|
||||||
import { ISplitviewPanel } from '../splitview/splitviewPanel';
|
import { ISplitviewPanel } from '../splitview/splitviewPanel';
|
||||||
import { GroupviewPanel } from '../groupview/groupviewPanel';
|
import { GroupviewPanel } from '../groupview/groupviewPanel';
|
||||||
import { Emitter, Event } from '../events';
|
import { Emitter, Event } from '../events';
|
||||||
@ -68,6 +68,14 @@ export class SplitviewApi implements CommonApi {
|
|||||||
return this.component.onDidLayoutChange;
|
return this.component.onDidLayoutChange;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
get onDidAddView(): Event<IView> {
|
||||||
|
return this.component.onDidAddView;
|
||||||
|
}
|
||||||
|
|
||||||
|
get onDidRemoveView(): Event<IView> {
|
||||||
|
return this.component.onDidRemoveView;
|
||||||
|
}
|
||||||
|
|
||||||
get orientation(): Orientation {
|
get orientation(): Orientation {
|
||||||
return this.component.orientation;
|
return this.component.orientation;
|
||||||
}
|
}
|
||||||
|
@ -51,7 +51,7 @@ export abstract class DraggablePaneviewPanel extends PaneviewPanel {
|
|||||||
isExpanded: boolean,
|
isExpanded: boolean,
|
||||||
disableDnd: boolean
|
disableDnd: boolean
|
||||||
) {
|
) {
|
||||||
super(id, component, headerComponent, orientation, isExpanded);
|
super(id, component, headerComponent, orientation, isExpanded, true);
|
||||||
|
|
||||||
if (!disableDnd) {
|
if (!disableDnd) {
|
||||||
this.initDragFeatures();
|
this.initDragFeatures();
|
||||||
|
@ -132,21 +132,21 @@ export class PaneviewComponent
|
|||||||
private readonly _onDidDrop = new Emitter<PaneviewDropEvent2>();
|
private readonly _onDidDrop = new Emitter<PaneviewDropEvent2>();
|
||||||
readonly onDidDrop: Event<PaneviewDropEvent2> = this._onDidDrop.event;
|
readonly onDidDrop: Event<PaneviewDropEvent2> = this._onDidDrop.event;
|
||||||
|
|
||||||
get onDidAddView() {
|
private readonly _onDidAddView = new Emitter<PaneviewPanel>();
|
||||||
return this._paneview.onDidAddView;
|
readonly onDidAddView = this._onDidAddView.event;
|
||||||
}
|
|
||||||
|
|
||||||
get onDidRemoveView() {
|
private readonly _onDidRemoveView = new Emitter<PaneviewPanel>();
|
||||||
return this._paneview.onDidRemoveView;
|
readonly onDidRemoveView = this._onDidRemoveView.event;
|
||||||
}
|
|
||||||
|
|
||||||
set paneview(value: Paneview) {
|
set paneview(value: Paneview) {
|
||||||
this._paneview = value;
|
this._paneview = value;
|
||||||
|
|
||||||
this._disposable.value = new CompositeDisposable(
|
this._disposable.value = new CompositeDisposable(
|
||||||
this.paneview.onDidChange(() => {
|
this._paneview.onDidChange(() => {
|
||||||
this._onDidLayoutChange.fire(undefined);
|
this._onDidLayoutChange.fire(undefined);
|
||||||
})
|
}),
|
||||||
|
this._paneview.onDidAddView((e) => this._onDidAddView.fire(e)),
|
||||||
|
this._paneview.onDidRemoveView((e) => this._onDidRemoveView.fire(e))
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -426,6 +426,11 @@ export class PaneviewComponent
|
|||||||
panel.orientation = this.paneview.orientation;
|
panel.orientation = this.paneview.orientation;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
setTimeout(() => {
|
||||||
|
// the original onDidAddView events are missed since they are fired before we can subcribe to them
|
||||||
|
this._onDidAddView.fire(panel);
|
||||||
|
}, 0);
|
||||||
|
|
||||||
return { size: view.size, view: panel };
|
return { size: view.size, view: panel };
|
||||||
}),
|
}),
|
||||||
},
|
},
|
||||||
|
@ -58,6 +58,7 @@ export interface IPaneviewPanel
|
|||||||
readonly maximumBodySize: number;
|
readonly maximumBodySize: number;
|
||||||
isExpanded(): boolean;
|
isExpanded(): boolean;
|
||||||
setExpanded(isExpanded: boolean): void;
|
setExpanded(isExpanded: boolean): void;
|
||||||
|
headerVisible: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export abstract class PaneviewPanel
|
export abstract class PaneviewPanel
|
||||||
@ -85,6 +86,8 @@ export abstract class PaneviewPanel
|
|||||||
private animationTimer: any | undefined;
|
private animationTimer: any | undefined;
|
||||||
private _orientation: Orientation;
|
private _orientation: Orientation;
|
||||||
|
|
||||||
|
private _headerVisible: boolean;
|
||||||
|
|
||||||
set orientation(value: Orientation) {
|
set orientation(value: Orientation) {
|
||||||
this._orientation = value;
|
this._orientation = value;
|
||||||
}
|
}
|
||||||
@ -138,16 +141,27 @@ export abstract class PaneviewPanel
|
|||||||
typeof value === 'number' ? value : Number.POSITIVE_INFINITY;
|
typeof value === 'number' ? value : Number.POSITIVE_INFINITY;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
get headerVisible(): boolean {
|
||||||
|
return this._headerVisible;
|
||||||
|
}
|
||||||
|
|
||||||
|
set headerVisible(value: boolean) {
|
||||||
|
this._headerVisible = value;
|
||||||
|
this.header!.style.display = value ? '' : 'none';
|
||||||
|
}
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
id: string,
|
id: string,
|
||||||
component: string,
|
component: string,
|
||||||
private readonly headerComponent: string | undefined,
|
private readonly headerComponent: string | undefined,
|
||||||
orientation: Orientation,
|
orientation: Orientation,
|
||||||
isExpanded: boolean
|
isExpanded: boolean,
|
||||||
|
isHeaderVisible: boolean
|
||||||
) {
|
) {
|
||||||
super(id, component, new PaneviewPanelApiImpl(id));
|
super(id, component, new PaneviewPanelApiImpl(id));
|
||||||
this.api.pane = this; // TODO cannot use 'this' before 'super'
|
this.api.pane = this; // TODO cannot use 'this' before 'super'
|
||||||
this._isExpanded = isExpanded;
|
this._isExpanded = isExpanded;
|
||||||
|
this._headerVisible = isHeaderVisible;
|
||||||
|
|
||||||
this._onDidChangeExpansionState.fire(this.isExpanded()); // initialize value
|
this._onDidChangeExpansionState.fire(this.isExpanded()); // initialize value
|
||||||
|
|
||||||
|
@ -111,7 +111,7 @@ export class Splitview {
|
|||||||
private readonly _onDidAddView = new Emitter<IView>();
|
private readonly _onDidAddView = new Emitter<IView>();
|
||||||
readonly onDidAddView = this._onDidAddView.event;
|
readonly onDidAddView = this._onDidAddView.event;
|
||||||
private readonly _onDidRemoveView = new Emitter<IView>();
|
private readonly _onDidRemoveView = new Emitter<IView>();
|
||||||
readonly onDidRemoveView = this._onDidAddView.event;
|
readonly onDidRemoveView = this._onDidRemoveView.event;
|
||||||
|
|
||||||
get size() {
|
get size() {
|
||||||
return this._size;
|
return this._size;
|
||||||
|
@ -4,6 +4,7 @@ import {
|
|||||||
MutableDisposable,
|
MutableDisposable,
|
||||||
} from '../lifecycle';
|
} from '../lifecycle';
|
||||||
import {
|
import {
|
||||||
|
IView,
|
||||||
LayoutPriority,
|
LayoutPriority,
|
||||||
Orientation,
|
Orientation,
|
||||||
Sizing,
|
Sizing,
|
||||||
@ -58,6 +59,8 @@ export interface ISplitviewComponent extends IDisposable {
|
|||||||
readonly width: number;
|
readonly width: number;
|
||||||
readonly length: number;
|
readonly length: number;
|
||||||
readonly orientation: Orientation;
|
readonly orientation: Orientation;
|
||||||
|
readonly onDidAddView: Event<IView>;
|
||||||
|
readonly onDidRemoveView: Event<IView>;
|
||||||
updateOptions(options: Partial<SplitviewComponentUpdateOptions>): void;
|
updateOptions(options: Partial<SplitviewComponentUpdateOptions>): void;
|
||||||
addPanel(options: AddSplitviewComponentOptions): void;
|
addPanel(options: AddSplitviewComponentOptions): void;
|
||||||
layout(width: number, height: number): void;
|
layout(width: number, height: number): void;
|
||||||
@ -90,6 +93,15 @@ export class SplitviewComponent
|
|||||||
private panels = new Map<string, IDisposable>();
|
private panels = new Map<string, IDisposable>();
|
||||||
private _options: SplitviewComponentOptions;
|
private _options: SplitviewComponentOptions;
|
||||||
|
|
||||||
|
private readonly _onDidAddView = new Emitter<IView>();
|
||||||
|
readonly onDidAddView = this._onDidAddView.event;
|
||||||
|
|
||||||
|
private readonly _onDidRemoveView = new Emitter<IView>();
|
||||||
|
readonly onDidRemoveView = this._onDidRemoveView.event;
|
||||||
|
|
||||||
|
private readonly _onDidLayoutChange = new Emitter<void>();
|
||||||
|
readonly onDidLayoutChange: Event<void> = this._onDidLayoutChange.event;
|
||||||
|
|
||||||
get options() {
|
get options() {
|
||||||
return this._options;
|
return this._options;
|
||||||
}
|
}
|
||||||
@ -108,13 +120,14 @@ export class SplitviewComponent
|
|||||||
this._disposable.value = new CompositeDisposable(
|
this._disposable.value = new CompositeDisposable(
|
||||||
this._splitview.onDidSashEnd(() => {
|
this._splitview.onDidSashEnd(() => {
|
||||||
this._onDidLayoutChange.fire(undefined);
|
this._onDidLayoutChange.fire(undefined);
|
||||||
})
|
}),
|
||||||
|
this._splitview.onDidAddView((e) => this._onDidAddView.fire(e)),
|
||||||
|
this._splitview.onDidRemoveView((e) =>
|
||||||
|
this._onDidRemoveView.fire(e)
|
||||||
|
)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
private readonly _onDidLayoutChange = new Emitter<void>();
|
|
||||||
readonly onDidLayoutChange: Event<void> = this._onDidLayoutChange.event;
|
|
||||||
|
|
||||||
get minimumSize() {
|
get minimumSize() {
|
||||||
return this.splitview.minimumSize;
|
return this.splitview.minimumSize;
|
||||||
}
|
}
|
||||||
@ -370,6 +383,10 @@ export class SplitviewComponent
|
|||||||
panel.orientation = orientation;
|
panel.orientation = orientation;
|
||||||
|
|
||||||
this.doAddView(panel);
|
this.doAddView(panel);
|
||||||
|
setTimeout(() => {
|
||||||
|
// the original onDidAddView events are missed since they are fired before we can subcribe to them
|
||||||
|
this._onDidAddView.fire(panel);
|
||||||
|
}, 0);
|
||||||
|
|
||||||
return { size: view.size, view: panel };
|
return { size: view.size, view: panel };
|
||||||
}),
|
}),
|
||||||
|
Loading…
Reference in New Issue
Block a user