mirror of
https://github.com/mathuo/dockview
synced 2025-10-31 20:28:06 +00:00
refactor: cleaner code
This commit is contained in:
parent
374d59f2cb
commit
88d6026335
@ -89,28 +89,28 @@ describe('dockviewComponent', () => {
|
||||
dockview.moveGroupOrPanel(group2, group1.id, 'panel3', Position.Center);
|
||||
|
||||
expect(dockview.activeGroup).toBe(group2);
|
||||
expect(dockview.activeGroup.group.activePanel).toBe(panel3);
|
||||
expect(dockview.activeGroup.group.indexOf(panel3)).toBe(1);
|
||||
expect(dockview.activeGroup.model.activePanel).toBe(panel3);
|
||||
expect(dockview.activeGroup.model.indexOf(panel3)).toBe(1);
|
||||
|
||||
dockview.moveToPrevious({ includePanel: true });
|
||||
expect(dockview.activeGroup).toBe(group2);
|
||||
expect(dockview.activeGroup.group.activePanel).toBe(panel1);
|
||||
expect(dockview.activeGroup.model.activePanel).toBe(panel1);
|
||||
|
||||
dockview.moveToNext({ includePanel: true });
|
||||
expect(dockview.activeGroup).toBe(group2);
|
||||
expect(dockview.activeGroup.group.activePanel).toBe(panel3);
|
||||
expect(dockview.activeGroup.model.activePanel).toBe(panel3);
|
||||
|
||||
dockview.moveToPrevious({ includePanel: false });
|
||||
expect(dockview.activeGroup).toBe(group1);
|
||||
expect(dockview.activeGroup.group.activePanel).toBe(panel4);
|
||||
expect(dockview.activeGroup.model.activePanel).toBe(panel4);
|
||||
|
||||
dockview.moveToPrevious({ includePanel: true });
|
||||
expect(dockview.activeGroup).toBe(group1);
|
||||
expect(dockview.activeGroup.group.activePanel).toBe(panel2);
|
||||
expect(dockview.activeGroup.model.activePanel).toBe(panel2);
|
||||
|
||||
dockview.moveToNext({ includePanel: false });
|
||||
expect(dockview.activeGroup).toBe(group2);
|
||||
expect(dockview.activeGroup.group.activePanel).toBe(panel3);
|
||||
expect(dockview.activeGroup.model.activePanel).toBe(panel3);
|
||||
});
|
||||
|
||||
test('remove group', () => {
|
||||
@ -142,8 +142,8 @@ describe('dockviewComponent', () => {
|
||||
|
||||
expect(dockview.size).toBe(2);
|
||||
expect(dockview.totalPanels).toBe(4);
|
||||
expect(panel1.group.group.size).toBe(2);
|
||||
expect(panel2.group.group.size).toBe(2);
|
||||
expect(panel1.group.model.size).toBe(2);
|
||||
expect(panel2.group.model.size).toBe(2);
|
||||
|
||||
dockview.removeGroup(panel1.group);
|
||||
|
||||
@ -263,13 +263,13 @@ describe('dockviewComponent', () => {
|
||||
|
||||
const group = panel1.group;
|
||||
|
||||
expect(group.group.size).toBe(2);
|
||||
expect(group.group.containsPanel(panel1)).toBeTruthy();
|
||||
expect(group.group.containsPanel(panel2)).toBeTruthy();
|
||||
expect(group.group.activePanel).toBe(panel2);
|
||||
expect(group.model.size).toBe(2);
|
||||
expect(group.model.containsPanel(panel1)).toBeTruthy();
|
||||
expect(group.model.containsPanel(panel2)).toBeTruthy();
|
||||
expect(group.model.activePanel).toBe(panel2);
|
||||
|
||||
expect(group.group.indexOf(panel1)).toBe(0);
|
||||
expect(group.group.indexOf(panel2)).toBe(1);
|
||||
expect(group.model.indexOf(panel1)).toBe(0);
|
||||
expect(group.model.indexOf(panel2)).toBe(1);
|
||||
|
||||
dockview.moveGroupOrPanel(group, group.id, 'panel1', Position.Right);
|
||||
|
||||
@ -277,12 +277,12 @@ describe('dockviewComponent', () => {
|
||||
expect(dockview.totalPanels).toBe(2);
|
||||
|
||||
expect(panel1.group).not.toBe(panel2.group);
|
||||
expect(panel1.group.group.size).toBe(1);
|
||||
expect(panel2.group.group.size).toBe(1);
|
||||
expect(panel1.group.group.containsPanel(panel1)).toBeTruthy();
|
||||
expect(panel2.group.group.containsPanel(panel2)).toBeTruthy();
|
||||
expect(panel1.group.group.activePanel).toBe(panel1);
|
||||
expect(panel2.group.group.activePanel).toBe(panel2);
|
||||
expect(panel1.group.model.size).toBe(1);
|
||||
expect(panel2.group.model.size).toBe(1);
|
||||
expect(panel1.group.model.containsPanel(panel1)).toBeTruthy();
|
||||
expect(panel2.group.model.containsPanel(panel2)).toBeTruthy();
|
||||
expect(panel1.group.model.activePanel).toBe(panel1);
|
||||
expect(panel2.group.model.activePanel).toBe(panel2);
|
||||
|
||||
await panel1.api.close();
|
||||
|
||||
|
||||
@ -235,7 +235,7 @@ describe('groupview', () => {
|
||||
activePanel: panel2,
|
||||
});
|
||||
|
||||
expect(groupview2.group.activePanel).toBe(panel2);
|
||||
expect(groupview2.model.activePanel).toBe(panel2);
|
||||
|
||||
expect(
|
||||
groupview2.element.querySelector('.content-part-panel1')
|
||||
@ -253,33 +253,33 @@ describe('groupview', () => {
|
||||
const panel2 = new TestPanel('panel2', jest.fn() as any);
|
||||
const panel3 = new TestPanel('panel3', jest.fn() as any);
|
||||
|
||||
groupview.group.openPanel(panel1);
|
||||
groupview.group.openPanel(panel2);
|
||||
groupview.group.openPanel(panel3);
|
||||
groupview.model.openPanel(panel1);
|
||||
groupview.model.openPanel(panel2);
|
||||
groupview.model.openPanel(panel3);
|
||||
|
||||
groupview.group.openPanel(panel2); // set active
|
||||
groupview.model.openPanel(panel2); // set active
|
||||
|
||||
groupview.group.moveToPrevious();
|
||||
expect(groupview.group.activePanel).toBe(panel1);
|
||||
groupview.model.moveToPrevious();
|
||||
expect(groupview.model.activePanel).toBe(panel1);
|
||||
|
||||
groupview.group.moveToPrevious({ suppressRoll: true });
|
||||
expect(groupview.group.activePanel).toBe(panel1);
|
||||
groupview.model.moveToPrevious({ suppressRoll: true });
|
||||
expect(groupview.model.activePanel).toBe(panel1);
|
||||
|
||||
groupview.group.moveToPrevious();
|
||||
expect(groupview.group.activePanel).toBe(panel3);
|
||||
groupview.model.moveToPrevious();
|
||||
expect(groupview.model.activePanel).toBe(panel3);
|
||||
|
||||
groupview.group.moveToNext({ suppressRoll: true });
|
||||
expect(groupview.group.activePanel).toBe(panel3);
|
||||
groupview.model.moveToNext({ suppressRoll: true });
|
||||
expect(groupview.model.activePanel).toBe(panel3);
|
||||
|
||||
groupview.group.moveToNext({ suppressRoll: false });
|
||||
expect(groupview.group.activePanel).toBe(panel1);
|
||||
groupview.model.moveToNext({ suppressRoll: false });
|
||||
expect(groupview.model.activePanel).toBe(panel1);
|
||||
|
||||
groupview.group.moveToPrevious({ suppressRoll: false });
|
||||
expect(groupview.group.activePanel).toBe(panel3);
|
||||
groupview.model.moveToPrevious({ suppressRoll: false });
|
||||
expect(groupview.model.activePanel).toBe(panel3);
|
||||
|
||||
groupview.group.moveToNext();
|
||||
groupview.group.moveToNext();
|
||||
expect(groupview.group.activePanel).toBe(panel2);
|
||||
groupview.model.moveToNext();
|
||||
groupview.model.moveToNext();
|
||||
expect(groupview.model.activePanel).toBe(panel2);
|
||||
});
|
||||
|
||||
test('default', () => {
|
||||
@ -298,12 +298,12 @@ describe('groupview', () => {
|
||||
const panel1 = new TestPanel('panel1', jest.fn() as any);
|
||||
const panel2 = new TestPanel('panel2', jest.fn() as any);
|
||||
|
||||
groupview.group.openPanel(panel1);
|
||||
groupview.group.openPanel(panel2);
|
||||
groupview.model.openPanel(panel1);
|
||||
groupview.model.openPanel(panel2);
|
||||
|
||||
const events: GroupDropEvent[] = [];
|
||||
|
||||
groupview.group.onDrop((event) => {
|
||||
groupview.model.onDrop((event) => {
|
||||
events.push(event);
|
||||
});
|
||||
|
||||
|
||||
@ -98,7 +98,7 @@ export class DockviewPanelApiImpl
|
||||
if (!this.group) {
|
||||
throw new Error(`panel ${this.id} has no group`);
|
||||
}
|
||||
return this.group.group.closePanel(this.panel);
|
||||
return this.group.model.closePanel(this.panel);
|
||||
}
|
||||
|
||||
public interceptOnCloseAction(interceptor: () => Promise<boolean>) {
|
||||
|
||||
@ -135,7 +135,8 @@ export interface LayoutDropEvent {
|
||||
|
||||
export class DockviewComponent
|
||||
extends BaseGrid<GroupviewPanel>
|
||||
implements IDockviewComponent {
|
||||
implements IDockviewComponent
|
||||
{
|
||||
private readonly panels = new Map<string, IValueDisposable<IGroupPanel>>();
|
||||
private readonly dirtyPanels = new Set<IGroupPanel>();
|
||||
private readonly debouncedDeque = debounce(
|
||||
@ -144,11 +145,11 @@ export class DockviewComponent
|
||||
);
|
||||
// events
|
||||
private readonly _onTabInteractionEvent = new Emitter<LayoutMouseEvent>();
|
||||
readonly onTabInteractionEvent: Event<LayoutMouseEvent> = this
|
||||
._onTabInteractionEvent.event;
|
||||
readonly onTabInteractionEvent: Event<LayoutMouseEvent> =
|
||||
this._onTabInteractionEvent.event;
|
||||
private readonly _onTabContextMenu = new Emitter<TabContextMenuEvent>();
|
||||
readonly onTabContextMenu: Event<TabContextMenuEvent> = this
|
||||
._onTabContextMenu.event;
|
||||
readonly onTabContextMenu: Event<TabContextMenuEvent> =
|
||||
this._onTabContextMenu.event;
|
||||
// everything else
|
||||
private drag = new MutableDisposable();
|
||||
private _deserializer: IPanelDeserializer | undefined;
|
||||
@ -270,7 +271,7 @@ export class DockviewComponent
|
||||
|
||||
const panel = this.panels.get(panelOptions.id)?.value;
|
||||
if (panel) {
|
||||
this.drag.value = panel.group!.group.startActiveDrag(panel);
|
||||
this.drag.value = panel.group!.model.startActiveDrag(panel);
|
||||
}
|
||||
|
||||
const data = JSON.stringify({
|
||||
@ -309,7 +310,7 @@ export class DockviewComponent
|
||||
throw new Error(`Panel ${panel.id} has no associated group`);
|
||||
}
|
||||
this.doSetGroupActive(panel.group);
|
||||
panel.group.group.openPanel(panel);
|
||||
panel.group.model.openPanel(panel);
|
||||
}
|
||||
|
||||
public moveToNext(options: MovementOptions = {}): void {
|
||||
@ -322,12 +323,12 @@ export class DockviewComponent
|
||||
|
||||
if (options.includePanel && options.group) {
|
||||
if (
|
||||
options.group.group.activePanel !==
|
||||
options.group.group.panels[
|
||||
options.group.group.panels.length - 1
|
||||
options.group.model.activePanel !==
|
||||
options.group.model.panels[
|
||||
options.group.model.panels.length - 1
|
||||
]
|
||||
) {
|
||||
options.group.group.moveToNext({ suppressRoll: true });
|
||||
options.group.model.moveToNext({ suppressRoll: true });
|
||||
return;
|
||||
}
|
||||
}
|
||||
@ -347,10 +348,10 @@ export class DockviewComponent
|
||||
|
||||
if (options.includePanel && options.group) {
|
||||
if (
|
||||
options.group.group.activePanel !==
|
||||
options.group.group.panels[0]
|
||||
options.group.model.activePanel !==
|
||||
options.group.model.panels[0]
|
||||
) {
|
||||
options.group.group.moveToPrevious({ suppressRoll: true });
|
||||
options.group.model.moveToPrevious({ suppressRoll: true });
|
||||
return;
|
||||
}
|
||||
}
|
||||
@ -511,7 +512,7 @@ export class DockviewComponent
|
||||
for (const entry of this.groups.entries()) {
|
||||
const [_, group] = entry;
|
||||
|
||||
const didCloseAll = await group.value.group.closeAllPanels();
|
||||
const didCloseAll = await group.value.model.closeAllPanels();
|
||||
if (!didCloseAll) {
|
||||
return false;
|
||||
}
|
||||
@ -523,7 +524,7 @@ export class DockviewComponent
|
||||
public setTabHeight(height: number | undefined): void {
|
||||
this.options.tabHeight = height;
|
||||
this.groups.forEach((value) => {
|
||||
value.value.group.tabHeight = height;
|
||||
value.value.model.tabHeight = height;
|
||||
});
|
||||
}
|
||||
|
||||
@ -569,7 +570,7 @@ export class DockviewComponent
|
||||
if (referenceGroup) {
|
||||
const target = toTarget(options.position?.direction || 'within');
|
||||
if (target === Position.Center) {
|
||||
referenceGroup.group.openPanel(panel);
|
||||
referenceGroup.model.openPanel(panel);
|
||||
} else {
|
||||
const location = getGridLocation(referenceGroup.element);
|
||||
const relativeLocation = getRelativeLocation(
|
||||
@ -652,8 +653,9 @@ export class DockviewComponent
|
||||
const group = this.createGroup();
|
||||
|
||||
if (options) {
|
||||
const referencePanel = this.panels.get(options.referencePanel)
|
||||
?.value;
|
||||
const referencePanel = this.panels.get(
|
||||
options.referencePanel
|
||||
)?.value;
|
||||
|
||||
if (!referencePanel) {
|
||||
throw new Error(
|
||||
@ -684,9 +686,9 @@ export class DockviewComponent
|
||||
}
|
||||
|
||||
public removeGroup(group: GroupviewPanel): void {
|
||||
const panels = [...group.group.panels]; // reassign since group panels will mutate
|
||||
const panels = [...group.model.panels]; // reassign since group panels will mutate
|
||||
panels.forEach((panel) => {
|
||||
group.group.removePanel(panel);
|
||||
group.model.removePanel(panel);
|
||||
this.unregisterPanel(panel);
|
||||
});
|
||||
|
||||
@ -707,7 +709,7 @@ export class DockviewComponent
|
||||
group! = this.createGroup();
|
||||
this.doAddGroup(group, location);
|
||||
|
||||
group.group.openPanel(panel);
|
||||
group.model.openPanel(panel);
|
||||
}
|
||||
|
||||
public moveGroupOrPanel(
|
||||
@ -723,18 +725,18 @@ export class DockviewComponent
|
||||
|
||||
if (!target || target === Position.Center) {
|
||||
const groupItem: IGroupPanel | undefined =
|
||||
sourceGroup?.group.removePanel(itemId) ||
|
||||
sourceGroup?.model.removePanel(itemId) ||
|
||||
this.panels.get(itemId)?.value;
|
||||
|
||||
if (!groupItem) {
|
||||
throw new Error(`No panel with id ${itemId}`);
|
||||
}
|
||||
|
||||
if (sourceGroup?.group.size === 0) {
|
||||
if (sourceGroup?.model.size === 0) {
|
||||
this.doRemoveGroup(sourceGroup);
|
||||
}
|
||||
|
||||
referenceGroup.group.openPanel(groupItem, { index });
|
||||
referenceGroup.model.openPanel(groupItem, { index });
|
||||
} else {
|
||||
const referenceLocation = getGridLocation(referenceGroup.element);
|
||||
const targetLocation = getRelativeLocation(
|
||||
@ -743,7 +745,7 @@ export class DockviewComponent
|
||||
target
|
||||
);
|
||||
|
||||
if (sourceGroup && sourceGroup.group.size < 2) {
|
||||
if (sourceGroup && sourceGroup.model.size < 2) {
|
||||
const [targetParentLocation, to] = tail(targetLocation);
|
||||
const sourceLocation = getGridLocation(sourceGroup.element);
|
||||
const [sourceParentLocation, from] = tail(sourceLocation);
|
||||
@ -775,7 +777,7 @@ export class DockviewComponent
|
||||
}
|
||||
} else {
|
||||
const groupItem: IGroupPanel | undefined =
|
||||
sourceGroup?.group.removePanel(itemId) ||
|
||||
sourceGroup?.model.removePanel(itemId) ||
|
||||
this.panels.get(itemId)?.value;
|
||||
|
||||
if (!groupItem) {
|
||||
@ -820,19 +822,19 @@ export class DockviewComponent
|
||||
const view = new GroupviewPanel(this, id, options);
|
||||
|
||||
if (typeof this.options.tabHeight === 'number') {
|
||||
view.group.tabHeight = this.options.tabHeight;
|
||||
view.model.tabHeight = this.options.tabHeight;
|
||||
}
|
||||
|
||||
if (!this.groups.has(view.id)) {
|
||||
const disposable = new CompositeDisposable(
|
||||
view.group.onMove((event) => {
|
||||
view.model.onMove((event) => {
|
||||
const { groupId, itemId, target, index } = event;
|
||||
this.moveGroupOrPanel(view, groupId, itemId, target, index);
|
||||
}),
|
||||
view.group.onDidGroupChange((event) => {
|
||||
view.model.onDidGroupChange((event) => {
|
||||
this._onGridEvent.fire(event);
|
||||
}),
|
||||
view.group.onDrop((event) => {
|
||||
view.model.onDrop((event) => {
|
||||
const dragEvent = event.event;
|
||||
const dataTransfer = dragEvent.dataTransfer;
|
||||
|
||||
@ -883,7 +885,7 @@ export class DockviewComponent
|
||||
|
||||
private findGroup(panel: IGroupPanel): GroupviewPanel | undefined {
|
||||
return Array.from(this.groups.values()).find((group) =>
|
||||
group.value.group.containsPanel(panel)
|
||||
group.value.model.containsPanel(panel)
|
||||
)?.value;
|
||||
}
|
||||
|
||||
|
||||
@ -157,10 +157,10 @@ export class DockviewGroupPanel
|
||||
this._group = group;
|
||||
this.api.group = group;
|
||||
|
||||
this.mutableDisposable.value = this._group.group.onDidGroupChange(
|
||||
this.mutableDisposable.value = this._group.model.onDidGroupChange(
|
||||
(ev) => {
|
||||
if (ev.kind === GroupChangeKind.GROUP_ACTIVE) {
|
||||
const isVisible = !!this._group?.group.isPanelActive(this);
|
||||
const isVisible = !!this._group?.model.isPanelActive(this);
|
||||
this.api._onDidActiveChange.fire({
|
||||
isActive: isGroupActive && isVisible,
|
||||
});
|
||||
@ -171,7 +171,7 @@ export class DockviewGroupPanel
|
||||
}
|
||||
);
|
||||
|
||||
const isPanelVisible = this._group.group.isPanelActive(this);
|
||||
const isPanelVisible = this._group.model.isPanelActive(this);
|
||||
|
||||
this.api._onDidActiveChange.fire({
|
||||
isActive: isGroupActive && isPanelVisible,
|
||||
@ -182,7 +182,7 @@ export class DockviewGroupPanel
|
||||
|
||||
this.view?.updateParentGroup(
|
||||
this._group,
|
||||
this._group.group.isPanelActive(this)
|
||||
this._group.model.isPanelActive(this)
|
||||
);
|
||||
}
|
||||
|
||||
@ -190,7 +190,7 @@ export class DockviewGroupPanel
|
||||
// the obtain the correct dimensions of the content panel we must deduct the tab height
|
||||
this.api._onDidPanelDimensionChange.fire({
|
||||
width,
|
||||
height: height - (this.group?.group.tabHeight || 0),
|
||||
height: height - (this.group?.model.tabHeight || 0),
|
||||
});
|
||||
|
||||
this.view?.layout(width, height);
|
||||
|
||||
@ -27,7 +27,8 @@ export interface BasePanelViewExported<T extends PanelApiImpl> {
|
||||
|
||||
export abstract class BasePanelView<T extends PanelApiImpl>
|
||||
extends CompositeDisposable
|
||||
implements IPanel, BasePanelViewExported<T> {
|
||||
implements IPanel, BasePanelViewExported<T>
|
||||
{
|
||||
private _height = 0;
|
||||
private _width = 0;
|
||||
private _element: HTMLElement;
|
||||
@ -87,8 +88,10 @@ export abstract class BasePanelView<T extends PanelApiImpl>
|
||||
this._height = height;
|
||||
this.api._onDidPanelDimensionChange.fire({ width, height });
|
||||
|
||||
if (this.part && this.params) {
|
||||
this.part.update(this.params.params);
|
||||
if (this.part) {
|
||||
if (this.params) {
|
||||
this.part.update(this.params.params);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -35,7 +35,8 @@ export interface IGridviewPanel
|
||||
|
||||
export abstract class GridviewPanel
|
||||
extends BasePanelView<GridviewPanelApiImpl>
|
||||
implements IGridPanelComponentView, IGridviewPanel {
|
||||
implements IGridPanelComponentView, IGridviewPanel
|
||||
{
|
||||
private _evaluatedMinimumWidth = 0;
|
||||
private _evaluatedMaximumWidth = Number.MAX_SAFE_INTEGER;
|
||||
private _evaluatedMinimumHeight = 0;
|
||||
@ -49,8 +50,8 @@ export abstract class GridviewPanel
|
||||
private _snap = false;
|
||||
|
||||
private readonly _onDidChange = new Emitter<IViewSize | undefined>();
|
||||
readonly onDidChange: Event<IViewSize | undefined> = this._onDidChange
|
||||
.event;
|
||||
readonly onDidChange: Event<IViewSize | undefined> =
|
||||
this._onDidChange.event;
|
||||
|
||||
get priority(): LayoutPriority | undefined {
|
||||
return this._priority;
|
||||
|
||||
@ -16,12 +16,18 @@ import { addDisposableListener, Emitter, Event } from '../events';
|
||||
import { IGridPanelView } from '../gridview/baseComponentGridview';
|
||||
import { IViewSize } from '../gridview/gridview';
|
||||
import { CompositeDisposable, Disposable, IDisposable } from '../lifecycle';
|
||||
import { PanelInitParameters, PanelUpdateEvent } from '../panel/types';
|
||||
import {
|
||||
IFrameworkPart,
|
||||
PanelInitParameters,
|
||||
PanelUpdateEvent,
|
||||
} from '../panel/types';
|
||||
import { IGroupPanel } from './groupPanel';
|
||||
import { ContentContainer, IContentContainer } from './panel/content';
|
||||
import { ITabsContainer, TabsContainer } from './titlebar/tabsContainer';
|
||||
import { IWatermarkRenderer } from './types';
|
||||
import { GroupviewPanel } from './groupviewPanel';
|
||||
import { focusedElement } from '../focusedElement';
|
||||
import { BasePanelView } from '../gridview/basePanelView';
|
||||
|
||||
export enum GroupChangeKind {
|
||||
GROUP_ACTIVE = 'GROUP_ACTIVE',
|
||||
@ -80,7 +86,7 @@ export interface IGroupview extends IDisposable, IGridPanelView {
|
||||
readonly isActive: boolean;
|
||||
readonly size: number;
|
||||
readonly panels: IGroupPanel[];
|
||||
tabHeight: number | undefined;
|
||||
readonly tabHeight: number | undefined;
|
||||
// state
|
||||
isPanelActive: (panel: IGroupPanel) => boolean;
|
||||
activePanel: IGroupPanel | undefined;
|
||||
@ -105,7 +111,7 @@ export interface IGroupview extends IDisposable, IGridPanelView {
|
||||
panel?: IGroupPanel;
|
||||
suppressRoll?: boolean;
|
||||
}): void;
|
||||
isAncestor(element: Element): boolean;
|
||||
isContentFocused(): boolean;
|
||||
updateActions(): void;
|
||||
}
|
||||
|
||||
@ -126,8 +132,8 @@ export class Groupview extends CompositeDisposable implements IGroupview {
|
||||
private mostRecentlyUsed: IGroupPanel[] = [];
|
||||
|
||||
private readonly _onDidChange = new Emitter<IViewSize | undefined>();
|
||||
readonly onDidChange: Event<IViewSize | undefined> = this._onDidChange
|
||||
.event;
|
||||
readonly onDidChange: Event<IViewSize | undefined> =
|
||||
this._onDidChange.event;
|
||||
|
||||
private _width = 0;
|
||||
private _height = 0;
|
||||
@ -141,8 +147,8 @@ export class Groupview extends CompositeDisposable implements IGroupview {
|
||||
readonly onDrop: Event<GroupDropEvent> = this._onDrop.event;
|
||||
|
||||
private readonly _onDidGroupChange = new Emitter<GroupChangeEvent>();
|
||||
readonly onDidGroupChange: Event<{ kind: GroupChangeKind }> = this
|
||||
._onDidGroupChange.event;
|
||||
readonly onDidGroupChange: Event<{ kind: GroupChangeKind }> =
|
||||
this._onDidGroupChange.event;
|
||||
|
||||
get element(): HTMLElement {
|
||||
throw new Error('not supported');
|
||||
@ -193,10 +199,92 @@ export class Groupview extends CompositeDisposable implements IGroupview {
|
||||
return Number.MAX_SAFE_INTEGER;
|
||||
}
|
||||
|
||||
isAncestor(element: Element): boolean {
|
||||
return (
|
||||
element === this.contentContainer.element ||
|
||||
isAncestor(element, this.contentContainer.element)
|
||||
constructor(
|
||||
private readonly container: HTMLElement,
|
||||
private accessor: IDockviewComponent,
|
||||
public id: string,
|
||||
private readonly options: GroupOptions,
|
||||
private readonly parent: GroupviewPanel
|
||||
) {
|
||||
super();
|
||||
|
||||
this.container.classList.add('groupview');
|
||||
|
||||
this.addDisposables(this._onMove, this._onDidGroupChange, this._onDrop);
|
||||
|
||||
this.tabsContainer = new TabsContainer(this.accessor, this.parent, {
|
||||
tabHeight: options.tabHeight,
|
||||
});
|
||||
this.contentContainer = new ContentContainer();
|
||||
this.dropTarget = new Droptarget(this.contentContainer.element, {
|
||||
isDirectional: true,
|
||||
id: this.accessor.id,
|
||||
isDisabled: () => {
|
||||
// disable the drop target if we only have one tab, and that is also the tab we are moving
|
||||
return (
|
||||
this._panels.length === 1 &&
|
||||
this.tabsContainer.hasActiveDragEvent
|
||||
);
|
||||
},
|
||||
enableExternalDragEvents:
|
||||
this.accessor.options.enableExternalDragEvents,
|
||||
});
|
||||
|
||||
container.append(
|
||||
this.tabsContainer.element,
|
||||
this.contentContainer.element
|
||||
);
|
||||
|
||||
this.addDisposables(
|
||||
this._onMove,
|
||||
this._onDidGroupChange,
|
||||
this.tabsContainer.onDropEvent((event) =>
|
||||
this.handleDropEvent(event.event, event.index)
|
||||
),
|
||||
this.contentContainer.onDidFocus(() => {
|
||||
this.accessor.doSetGroupActive(this.parent, true);
|
||||
}),
|
||||
this.contentContainer.onDidBlur(() => {
|
||||
// this._activePanel?.api._ondid
|
||||
}),
|
||||
this.dropTarget.onDidChange((event) => {
|
||||
// if we've center dropped on ourself then ignore
|
||||
if (
|
||||
event.position === Position.Center &&
|
||||
this.tabsContainer.hasActiveDragEvent
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.handleDropEvent(event);
|
||||
})
|
||||
);
|
||||
|
||||
if (this.options?.panels) {
|
||||
this.options.panels.forEach((panel) => {
|
||||
this.doAddPanel(panel);
|
||||
});
|
||||
}
|
||||
|
||||
if (this.options?.activePanel) {
|
||||
this.openPanel(this.options.activePanel);
|
||||
}
|
||||
}
|
||||
|
||||
initialize() {
|
||||
// must be run after the constructor otherwise this.parent may not be
|
||||
// correctly initialized
|
||||
this.setActive(this.isActive, true, true);
|
||||
this.updateContainer();
|
||||
}
|
||||
|
||||
isContentFocused() {
|
||||
if (!focusedElement.element) {
|
||||
return false;
|
||||
}
|
||||
return isAncestor(
|
||||
focusedElement.element,
|
||||
this.contentContainer.element
|
||||
);
|
||||
}
|
||||
|
||||
@ -286,84 +374,6 @@ export class Groupview extends CompositeDisposable implements IGroupview {
|
||||
return this.panels.includes(panel);
|
||||
}
|
||||
|
||||
constructor(
|
||||
private readonly container: HTMLElement,
|
||||
private accessor: IDockviewComponent,
|
||||
public id: string,
|
||||
private readonly options: GroupOptions,
|
||||
private readonly parent: GroupviewPanel
|
||||
) {
|
||||
super();
|
||||
|
||||
this.container.classList.add('groupview');
|
||||
|
||||
this.addDisposables(this._onMove, this._onDidGroupChange, this._onDrop);
|
||||
|
||||
this.tabsContainer = new TabsContainer(this.accessor, this.parent, {
|
||||
tabHeight: options.tabHeight,
|
||||
});
|
||||
this.contentContainer = new ContentContainer();
|
||||
this.dropTarget = new Droptarget(this.contentContainer.element, {
|
||||
isDirectional: true,
|
||||
id: this.accessor.id,
|
||||
isDisabled: () => {
|
||||
// disable the drop target if we only have one tab, and that is also the tab we are moving
|
||||
return (
|
||||
this._panels.length === 1 &&
|
||||
this.tabsContainer.hasActiveDragEvent
|
||||
);
|
||||
},
|
||||
enableExternalDragEvents: this.accessor.options
|
||||
.enableExternalDragEvents,
|
||||
});
|
||||
|
||||
container.append(
|
||||
this.tabsContainer.element,
|
||||
this.contentContainer.element
|
||||
);
|
||||
|
||||
this.addDisposables(
|
||||
this._onMove,
|
||||
this._onDidGroupChange,
|
||||
this.tabsContainer.onDropEvent((event) =>
|
||||
this.handleDropEvent(event.event, event.index)
|
||||
),
|
||||
this.contentContainer.onDidFocus(() => {
|
||||
this.accessor.doSetGroupActive(this.parent, true);
|
||||
}),
|
||||
this.contentContainer.onDidBlur(() => {
|
||||
// this._activePanel?.api._ondid
|
||||
}),
|
||||
this.dropTarget.onDidChange((event) => {
|
||||
// if we've center dropped on ourself then ignore
|
||||
if (
|
||||
event.position === Position.Center &&
|
||||
this.tabsContainer.hasActiveDragEvent
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.handleDropEvent(event);
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
bootstrap() {
|
||||
if (this.options?.panels) {
|
||||
this.options.panels.forEach((panel) => {
|
||||
this.doAddPanel(panel);
|
||||
});
|
||||
}
|
||||
|
||||
if (this.options?.activePanel) {
|
||||
this.openPanel(this.options.activePanel);
|
||||
}
|
||||
|
||||
this.setActive(this.isActive, true, true);
|
||||
|
||||
this.updateContainer();
|
||||
}
|
||||
|
||||
init(params: PanelInitParameters) {
|
||||
//noop
|
||||
}
|
||||
|
||||
@ -1,47 +1,30 @@
|
||||
import { IFrameworkPart } from '../panel/types';
|
||||
import { IDockviewComponent } from '../dockview/dockviewComponent';
|
||||
import {
|
||||
GridviewPanelApiImpl,
|
||||
GridviewPanelApi,
|
||||
} from '../api/gridviewPanelApi';
|
||||
import { GridviewPanelApiImpl } from '../api/gridviewPanelApi';
|
||||
import { Groupview, GroupOptions } from './groupview';
|
||||
import { GridviewPanel } from '../gridview/gridviewPanel';
|
||||
|
||||
interface IGroupApi extends GridviewPanelApi {}
|
||||
|
||||
class GroupApi extends GridviewPanelApiImpl implements IGroupApi {
|
||||
private _value?: Groupview;
|
||||
|
||||
set group(value: Groupview) {
|
||||
this._value = value;
|
||||
}
|
||||
|
||||
constructor(id: string) {
|
||||
super(id);
|
||||
}
|
||||
}
|
||||
|
||||
export class GroupviewPanel extends GridviewPanel {
|
||||
private readonly _group: Groupview;
|
||||
private readonly _model: Groupview;
|
||||
|
||||
get group(): Groupview {
|
||||
return this._group;
|
||||
get model(): Groupview {
|
||||
return this._model;
|
||||
}
|
||||
|
||||
get minimumHeight() {
|
||||
return this._group.minimumHeight;
|
||||
return this._model.minimumHeight;
|
||||
}
|
||||
|
||||
get maximumHeight() {
|
||||
return this._group.maximumHeight;
|
||||
return this._model.maximumHeight;
|
||||
}
|
||||
|
||||
get minimumWidth() {
|
||||
return this._group.minimumWidth;
|
||||
return this._model.minimumWidth;
|
||||
}
|
||||
|
||||
get maximumWidth() {
|
||||
return this._group.maximumWidth;
|
||||
return this._model.maximumWidth;
|
||||
}
|
||||
|
||||
constructor(
|
||||
@ -49,29 +32,27 @@ export class GroupviewPanel extends GridviewPanel {
|
||||
id: string,
|
||||
options: GroupOptions
|
||||
) {
|
||||
super(id, 'groupview_default', new GroupApi(id));
|
||||
super(id, 'groupview_default', new GridviewPanelApiImpl(id));
|
||||
|
||||
this._group = new Groupview(this.element, accessor, id, options, this);
|
||||
|
||||
(this.api as GroupApi).group = this._group;
|
||||
this.group.bootstrap();
|
||||
this._model = new Groupview(this.element, accessor, id, options, this);
|
||||
this.model.initialize();
|
||||
}
|
||||
|
||||
setActive(isActive: boolean): void {
|
||||
super.setActive(isActive);
|
||||
this.group.setActive(isActive);
|
||||
this.model.setActive(isActive);
|
||||
}
|
||||
|
||||
layout(width: number, height: number) {
|
||||
super.layout(width, height);
|
||||
this.group.layout(width, height);
|
||||
this.model.layout(width, height);
|
||||
}
|
||||
|
||||
getComponent(): IFrameworkPart {
|
||||
return this._group;
|
||||
return this._model;
|
||||
}
|
||||
|
||||
toJSON(): any {
|
||||
return this.group.toJSON();
|
||||
return this.model.toJSON();
|
||||
}
|
||||
}
|
||||
|
||||
@ -7,13 +7,6 @@ import { Emitter, Event } from '../../events';
|
||||
import { trackFocus } from '../../dom';
|
||||
import { IGroupPanel } from '../groupPanel';
|
||||
|
||||
export interface IRenderable {
|
||||
id: string;
|
||||
element: HTMLElement;
|
||||
onDidFocus?: Event<void>;
|
||||
onDidBlur?: Event<void>;
|
||||
}
|
||||
|
||||
export interface IContentContainer extends IDisposable {
|
||||
onDidFocus: Event<void>;
|
||||
onDidBlur: Event<void>;
|
||||
@ -25,76 +18,10 @@ export interface IContentContainer extends IDisposable {
|
||||
hide(): void;
|
||||
}
|
||||
|
||||
export interface HostedPanelOptions {
|
||||
id: string;
|
||||
parent?: HTMLElement;
|
||||
}
|
||||
|
||||
export class HostedPanel implements IRenderable, IDisposable {
|
||||
private readonly _element: HTMLElement;
|
||||
|
||||
get element() {
|
||||
return this._element;
|
||||
}
|
||||
|
||||
get id() {
|
||||
return this.panel.id;
|
||||
}
|
||||
|
||||
constructor(
|
||||
private readonly panel: IGroupPanel,
|
||||
private readonly options: HostedPanelOptions
|
||||
) {
|
||||
if (!options.parent) {
|
||||
options.parent = document.getElementById('app') as HTMLElement;
|
||||
options.parent.style.position = 'relative';
|
||||
}
|
||||
|
||||
this._element = document.createElement('div');
|
||||
this._element.style.visibility = 'hidden';
|
||||
this._element.style.overflow = 'hidden';
|
||||
// this._element.style.pointerEvents = 'none';
|
||||
this._element.id = `webivew-${options.id}`;
|
||||
|
||||
options.parent.appendChild(this._element);
|
||||
}
|
||||
|
||||
hide() {
|
||||
this._element.style.visibility = 'hidden';
|
||||
}
|
||||
|
||||
show() {
|
||||
this._element.style.visibility = 'visible';
|
||||
}
|
||||
|
||||
layout(
|
||||
element: HTMLElement,
|
||||
dimension?: { width: number; height: number }
|
||||
) {
|
||||
if (!this.element || !this.element.parentElement) {
|
||||
return;
|
||||
}
|
||||
const frameRect = element.getBoundingClientRect();
|
||||
const containerRect = this.element.parentElement.getBoundingClientRect();
|
||||
this.element.style.position = 'absolute';
|
||||
this.element.style.top = `${frameRect.top - containerRect.top}px`;
|
||||
this.element.style.left = `${frameRect.left - containerRect.left}px`;
|
||||
this.element.style.width = `${
|
||||
dimension ? dimension.width : frameRect.width
|
||||
}px`;
|
||||
this.element.style.height = `${
|
||||
dimension ? dimension.height : frameRect.height
|
||||
}px`;
|
||||
}
|
||||
|
||||
dispose() {
|
||||
this._element.remove();
|
||||
}
|
||||
}
|
||||
|
||||
export class ContentContainer
|
||||
extends CompositeDisposable
|
||||
implements IContentContainer {
|
||||
implements IContentContainer
|
||||
{
|
||||
private _element: HTMLElement;
|
||||
private panel: IGroupPanel | undefined;
|
||||
private disposable = new MutableDisposable();
|
||||
@ -145,8 +72,8 @@ export class ContentContainer
|
||||
const disposable = new CompositeDisposable();
|
||||
|
||||
if (this.panel.view) {
|
||||
const _onDidFocus: Event<void> = this.panel.view.content
|
||||
.onDidFocus!;
|
||||
const _onDidFocus: Event<void> =
|
||||
this.panel.view.content.onDidFocus!;
|
||||
const _onDidBlur: Event<void> = this.panel.view.content.onDidBlur!;
|
||||
|
||||
const { onDidFocus, onDidBlur } = trackFocus(this._element);
|
||||
|
||||
71
packages/dockview/src/groupview/panel/hostedPanel.ts
Normal file
71
packages/dockview/src/groupview/panel/hostedPanel.ts
Normal file
@ -0,0 +1,71 @@
|
||||
import { IDisposable } from '../../lifecycle';
|
||||
import { IGroupPanel } from '../groupPanel';
|
||||
import { IRenderable } from '../types';
|
||||
|
||||
export interface HostedPanelOptions {
|
||||
id: string;
|
||||
parent?: HTMLElement;
|
||||
}
|
||||
|
||||
export class HostedPanel implements IRenderable, IDisposable {
|
||||
private readonly _element: HTMLElement;
|
||||
|
||||
get element() {
|
||||
return this._element;
|
||||
}
|
||||
|
||||
get id() {
|
||||
return this.panel.id;
|
||||
}
|
||||
|
||||
constructor(
|
||||
private readonly panel: IGroupPanel,
|
||||
private readonly options: HostedPanelOptions
|
||||
) {
|
||||
if (!options.parent) {
|
||||
options.parent = document.getElementById('app') as HTMLElement;
|
||||
options.parent.style.position = 'relative';
|
||||
}
|
||||
|
||||
this._element = document.createElement('div');
|
||||
this._element.style.visibility = 'hidden';
|
||||
this._element.style.overflow = 'hidden';
|
||||
// this._element.style.pointerEvents = 'none';
|
||||
this._element.id = `webivew-${options.id}`;
|
||||
|
||||
options.parent.appendChild(this._element);
|
||||
}
|
||||
|
||||
hide() {
|
||||
this._element.style.visibility = 'hidden';
|
||||
}
|
||||
|
||||
show() {
|
||||
this._element.style.visibility = 'visible';
|
||||
}
|
||||
|
||||
layout(
|
||||
element: HTMLElement,
|
||||
dimension?: { width: number; height: number }
|
||||
) {
|
||||
if (!this.element || !this.element.parentElement) {
|
||||
return;
|
||||
}
|
||||
const frameRect = element.getBoundingClientRect();
|
||||
const containerRect =
|
||||
this.element.parentElement.getBoundingClientRect();
|
||||
this.element.style.position = 'absolute';
|
||||
this.element.style.top = `${frameRect.top - containerRect.top}px`;
|
||||
this.element.style.left = `${frameRect.left - containerRect.left}px`;
|
||||
this.element.style.width = `${
|
||||
dimension ? dimension.width : frameRect.width
|
||||
}px`;
|
||||
this.element.style.height = `${
|
||||
dimension ? dimension.height : frameRect.height
|
||||
}px`;
|
||||
}
|
||||
|
||||
dispose() {
|
||||
this._element.remove();
|
||||
}
|
||||
}
|
||||
@ -8,7 +8,6 @@ import { ITab, MouseEventKind, Tab } from '../tab';
|
||||
import { removeClasses, addClasses } from '../../dom';
|
||||
import { DroptargetEvent, Position } from '../../dnd/droptarget';
|
||||
import { last } from '../../array';
|
||||
import { focusedElement } from '../../focusedElement';
|
||||
import { IGroupPanel } from '../groupPanel';
|
||||
import { IDockviewComponent } from '../../dockview/dockviewComponent';
|
||||
import { LocalSelectionTransfer } from '../../dnd/dataTransfer';
|
||||
@ -40,7 +39,8 @@ export interface ITabsContainer extends IDisposable {
|
||||
|
||||
export class TabsContainer
|
||||
extends CompositeDisposable
|
||||
implements ITabsContainer {
|
||||
implements ITabsContainer
|
||||
{
|
||||
private readonly _element: HTMLElement;
|
||||
private readonly tabContainer: HTMLElement;
|
||||
private readonly actionContainer: HTMLElement;
|
||||
@ -281,8 +281,8 @@ export class TabsContainer
|
||||
const disposable = CompositeDisposable.from(
|
||||
tabToAdd.onChanged((event) => {
|
||||
const alreadyFocused =
|
||||
panel.id === this.group.group.activePanel?.id &&
|
||||
this.group.group.isAncestor(focusedElement.element!);
|
||||
panel.id === this.group.model.activePanel?.id &&
|
||||
this.group.model.isContentFocused();
|
||||
this.accessor.fireMouseEvent({ ...event, panel, tab: true });
|
||||
|
||||
const isLeftClick = event.event.button === 0;
|
||||
@ -293,7 +293,7 @@ export class TabsContainer
|
||||
|
||||
switch (event.kind) {
|
||||
case MouseEventKind.CLICK:
|
||||
this.group.group.openPanel(panel, {
|
||||
this.group.model.openPanel(panel, {
|
||||
skipFocus: alreadyFocused,
|
||||
});
|
||||
break;
|
||||
|
||||
@ -7,6 +7,13 @@ import { GroupviewPanel } from './groupviewPanel';
|
||||
import { Event } from '../events';
|
||||
import { WrappedTab } from '../dockview/components/tab/defaultTab';
|
||||
|
||||
export interface IRenderable {
|
||||
id: string;
|
||||
element: HTMLElement;
|
||||
onDidFocus?: Event<void>;
|
||||
onDidBlur?: Event<void>;
|
||||
}
|
||||
|
||||
export interface HeaderPartInitParameters {
|
||||
title: string;
|
||||
suppressClosable?: boolean;
|
||||
|
||||
@ -15,10 +15,6 @@ import { PanelCollection, PanelParameters } from '../types';
|
||||
import { watchElementResize } from '../../dom';
|
||||
import { IContentRenderer, ITabRenderer } from '../../groupview/types';
|
||||
|
||||
export interface PanelCollection1<T extends IDockviewPanelProps> {
|
||||
[name: string]: React.FunctionComponent<T>;
|
||||
}
|
||||
|
||||
export interface IGroupPanelBaseProps<T extends {} = Record<string, any>>
|
||||
extends PanelParameters<T> {
|
||||
api: DockviewPanelApi;
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user