feat: Improve onDidAdd/onDidRemove events for pane/splitview

This commit is contained in:
mathuo 2022-02-22 21:10:06 +00:00
parent 6ba8015502
commit 67b4b2502f
No known key found for this signature in database
GPG Key ID: C6EEDEFD6CA07281
9 changed files with 210 additions and 17 deletions

View 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();
});
});

View File

@ -12,7 +12,7 @@ import { Orientation } from '../../splitview/core/splitview';
class TestPanel extends PaneviewPanel {
constructor(id: string, component: string) {
super(id, component, 'header', Orientation.VERTICAL, false);
super(id, component, 'header', Orientation.VERTICAL, false, true);
}
getHeaderComponent() {

View File

@ -1,5 +1,6 @@
import { last } from '../../../array';
import { Emitter } from '../../../events';
import { CompositeDisposable } from '../../../lifecycle';
import {
IView,
LayoutPriority,
@ -522,4 +523,47 @@ describe('splitview', () => {
]).toEqual([80, 100, 120]);
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();
});
});

View File

@ -27,7 +27,7 @@ import {
SerializedSplitview,
SplitviewComponentUpdateOptions,
} from '../splitview/splitviewComponent';
import { Orientation, Sizing } from '../splitview/core/splitview';
import { IView, Orientation, Sizing } from '../splitview/core/splitview';
import { ISplitviewPanel } from '../splitview/splitviewPanel';
import { GroupviewPanel } from '../groupview/groupviewPanel';
import { Emitter, Event } from '../events';
@ -68,6 +68,14 @@ export class SplitviewApi implements CommonApi {
return this.component.onDidLayoutChange;
}
get onDidAddView(): Event<IView> {
return this.component.onDidAddView;
}
get onDidRemoveView(): Event<IView> {
return this.component.onDidRemoveView;
}
get orientation(): Orientation {
return this.component.orientation;
}

View File

@ -51,7 +51,7 @@ export abstract class DraggablePaneviewPanel extends PaneviewPanel {
isExpanded: boolean,
disableDnd: boolean
) {
super(id, component, headerComponent, orientation, isExpanded);
super(id, component, headerComponent, orientation, isExpanded, true);
if (!disableDnd) {
this.initDragFeatures();

View File

@ -132,21 +132,21 @@ export class PaneviewComponent
private readonly _onDidDrop = new Emitter<PaneviewDropEvent2>();
readonly onDidDrop: Event<PaneviewDropEvent2> = this._onDidDrop.event;
get onDidAddView() {
return this._paneview.onDidAddView;
}
private readonly _onDidAddView = new Emitter<PaneviewPanel>();
readonly onDidAddView = this._onDidAddView.event;
get onDidRemoveView() {
return this._paneview.onDidRemoveView;
}
private readonly _onDidRemoveView = new Emitter<PaneviewPanel>();
readonly onDidRemoveView = this._onDidRemoveView.event;
set paneview(value: Paneview) {
this._paneview = value;
this._disposable.value = new CompositeDisposable(
this.paneview.onDidChange(() => {
this._paneview.onDidChange(() => {
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;
});
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 };
}),
},

View File

@ -58,6 +58,7 @@ export interface IPaneviewPanel
readonly maximumBodySize: number;
isExpanded(): boolean;
setExpanded(isExpanded: boolean): void;
headerVisible: boolean;
}
export abstract class PaneviewPanel
@ -85,6 +86,8 @@ export abstract class PaneviewPanel
private animationTimer: any | undefined;
private _orientation: Orientation;
private _headerVisible: boolean;
set orientation(value: Orientation) {
this._orientation = value;
}
@ -138,16 +141,27 @@ export abstract class PaneviewPanel
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(
id: string,
component: string,
private readonly headerComponent: string | undefined,
orientation: Orientation,
isExpanded: boolean
isExpanded: boolean,
isHeaderVisible: boolean
) {
super(id, component, new PaneviewPanelApiImpl(id));
this.api.pane = this; // TODO cannot use 'this' before 'super'
this._isExpanded = isExpanded;
this._headerVisible = isHeaderVisible;
this._onDidChangeExpansionState.fire(this.isExpanded()); // initialize value

View File

@ -111,7 +111,7 @@ export class Splitview {
private readonly _onDidAddView = new Emitter<IView>();
readonly onDidAddView = this._onDidAddView.event;
private readonly _onDidRemoveView = new Emitter<IView>();
readonly onDidRemoveView = this._onDidAddView.event;
readonly onDidRemoveView = this._onDidRemoveView.event;
get size() {
return this._size;

View File

@ -4,6 +4,7 @@ import {
MutableDisposable,
} from '../lifecycle';
import {
IView,
LayoutPriority,
Orientation,
Sizing,
@ -58,6 +59,8 @@ export interface ISplitviewComponent extends IDisposable {
readonly width: number;
readonly length: number;
readonly orientation: Orientation;
readonly onDidAddView: Event<IView>;
readonly onDidRemoveView: Event<IView>;
updateOptions(options: Partial<SplitviewComponentUpdateOptions>): void;
addPanel(options: AddSplitviewComponentOptions): void;
layout(width: number, height: number): void;
@ -90,6 +93,15 @@ export class SplitviewComponent
private panels = new Map<string, IDisposable>();
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() {
return this._options;
}
@ -108,13 +120,14 @@ export class SplitviewComponent
this._disposable.value = new CompositeDisposable(
this._splitview.onDidSashEnd(() => {
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() {
return this.splitview.minimumSize;
}
@ -370,6 +383,10 @@ export class SplitviewComponent
panel.orientation = orientation;
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 };
}),