mirror of
https://github.com/mathuo/dockview
synced 2025-05-04 18:48:26 +00:00
work in progress
This commit is contained in:
parent
8833a973b9
commit
2aa700bca0
@ -10,7 +10,7 @@ export abstract class DragHandler extends CompositeDisposable {
|
|||||||
private readonly dataDisposable = new MutableDisposable();
|
private readonly dataDisposable = new MutableDisposable();
|
||||||
private readonly pointerEventsDisposable = new MutableDisposable();
|
private readonly pointerEventsDisposable = new MutableDisposable();
|
||||||
|
|
||||||
private readonly _onDragStart = new Emitter<void>();
|
private readonly _onDragStart = new Emitter<DragEvent>();
|
||||||
readonly onDragStart = this._onDragStart.event;
|
readonly onDragStart = this._onDragStart.event;
|
||||||
|
|
||||||
constructor(protected readonly el: HTMLElement) {
|
constructor(protected readonly el: HTMLElement) {
|
||||||
@ -35,7 +35,9 @@ export abstract class DragHandler extends CompositeDisposable {
|
|||||||
this.addDisposables(
|
this.addDisposables(
|
||||||
this._onDragStart,
|
this._onDragStart,
|
||||||
addDisposableListener(this.el, 'dragstart', (event) => {
|
addDisposableListener(this.el, 'dragstart', (event) => {
|
||||||
if (this.isCancelled(event)) {
|
this._onDragStart.fire(event);
|
||||||
|
|
||||||
|
if (event.defaultPrevented || this.isCancelled(event)) {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -11,9 +11,37 @@ import { DockviewDropTargets, ITabRenderer } from '../../types';
|
|||||||
import { DockviewGroupPanel } from '../../dockviewGroupPanel';
|
import { DockviewGroupPanel } from '../../dockviewGroupPanel';
|
||||||
import { DroptargetEvent, Droptarget } from '../../../dnd/droptarget';
|
import { DroptargetEvent, Droptarget } from '../../../dnd/droptarget';
|
||||||
import { DragHandler } from '../../../dnd/abstractDragHandler';
|
import { DragHandler } from '../../../dnd/abstractDragHandler';
|
||||||
|
import { IDockviewPanel } from '../../dockviewPanel';
|
||||||
|
|
||||||
|
class TabDragHandler extends DragHandler {
|
||||||
|
private readonly panelTransfer =
|
||||||
|
LocalSelectionTransfer.getInstance<PanelTransfer>();
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
element: HTMLElement,
|
||||||
|
private readonly accessor: DockviewComponent,
|
||||||
|
private readonly group: DockviewGroupPanel,
|
||||||
|
private readonly panel: IDockviewPanel
|
||||||
|
) {
|
||||||
|
super(element);
|
||||||
|
}
|
||||||
|
|
||||||
|
getData(): IDisposable {
|
||||||
|
this.panelTransfer.setData(
|
||||||
|
[new PanelTransfer(this.accessor.id, this.group.id, this.panel.id)],
|
||||||
|
PanelTransfer.prototype
|
||||||
|
);
|
||||||
|
|
||||||
|
return {
|
||||||
|
dispose: () => {
|
||||||
|
this.panelTransfer.clearData(PanelTransfer.prototype);
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
export interface ITab extends IDisposable {
|
export interface ITab extends IDisposable {
|
||||||
readonly panelId: string;
|
readonly panel: IDockviewPanel;
|
||||||
readonly element: HTMLElement;
|
readonly element: HTMLElement;
|
||||||
setContent: (element: ITabRenderer) => void;
|
setContent: (element: ITabRenderer) => void;
|
||||||
onChanged: Event<MouseEvent>;
|
onChanged: Event<MouseEvent>;
|
||||||
@ -24,7 +52,7 @@ export interface ITab extends IDisposable {
|
|||||||
export class Tab extends CompositeDisposable implements ITab {
|
export class Tab extends CompositeDisposable implements ITab {
|
||||||
private readonly _element: HTMLElement;
|
private readonly _element: HTMLElement;
|
||||||
private readonly droptarget: Droptarget;
|
private readonly droptarget: Droptarget;
|
||||||
private content?: ITabRenderer;
|
private content: ITabRenderer | undefined = undefined;
|
||||||
|
|
||||||
private readonly _onChanged = new Emitter<MouseEvent>();
|
private readonly _onChanged = new Emitter<MouseEvent>();
|
||||||
readonly onChanged: Event<MouseEvent> = this._onChanged.event;
|
readonly onChanged: Event<MouseEvent> = this._onChanged.event;
|
||||||
@ -32,12 +60,15 @@ export class Tab extends CompositeDisposable implements ITab {
|
|||||||
private readonly _onDropped = new Emitter<DroptargetEvent>();
|
private readonly _onDropped = new Emitter<DroptargetEvent>();
|
||||||
readonly onDrop: Event<DroptargetEvent> = this._onDropped.event;
|
readonly onDrop: Event<DroptargetEvent> = this._onDropped.event;
|
||||||
|
|
||||||
|
private readonly _onDragStart = new Emitter<DragEvent>();
|
||||||
|
readonly onDragStart = this._onDragStart.event;
|
||||||
|
|
||||||
public get element(): HTMLElement {
|
public get element(): HTMLElement {
|
||||||
return this._element;
|
return this._element;
|
||||||
}
|
}
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
public readonly panelId: string,
|
public readonly panel: IDockviewPanel,
|
||||||
private readonly accessor: DockviewComponent,
|
private readonly accessor: DockviewComponent,
|
||||||
private readonly group: DockviewGroupPanel
|
private readonly group: DockviewGroupPanel
|
||||||
) {
|
) {
|
||||||
@ -50,38 +81,11 @@ export class Tab extends CompositeDisposable implements ITab {
|
|||||||
|
|
||||||
toggleClass(this.element, 'inactive-tab', true);
|
toggleClass(this.element, 'inactive-tab', true);
|
||||||
|
|
||||||
this.addDisposables(
|
const dragHandler = new TabDragHandler(
|
||||||
this._onChanged,
|
this._element,
|
||||||
this._onDropped,
|
this.accessor,
|
||||||
new (class Handler extends DragHandler {
|
this.group,
|
||||||
private readonly panelTransfer =
|
this.panel
|
||||||
LocalSelectionTransfer.getInstance<PanelTransfer>();
|
|
||||||
|
|
||||||
getData(): IDisposable {
|
|
||||||
this.panelTransfer.setData(
|
|
||||||
[new PanelTransfer(accessor.id, group.id, panelId)],
|
|
||||||
PanelTransfer.prototype
|
|
||||||
);
|
|
||||||
|
|
||||||
return {
|
|
||||||
dispose: () => {
|
|
||||||
this.panelTransfer.clearData(
|
|
||||||
PanelTransfer.prototype
|
|
||||||
);
|
|
||||||
},
|
|
||||||
};
|
|
||||||
}
|
|
||||||
})(this._element)
|
|
||||||
);
|
|
||||||
|
|
||||||
this.addDisposables(
|
|
||||||
addDisposableListener(this._element, 'mousedown', (event) => {
|
|
||||||
if (event.defaultPrevented) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
this._onChanged.fire(event);
|
|
||||||
})
|
|
||||||
);
|
);
|
||||||
|
|
||||||
this.droptarget = new Droptarget(this._element, {
|
this.droptarget = new Droptarget(this._element, {
|
||||||
@ -102,7 +106,7 @@ export class Tab extends CompositeDisposable implements ITab {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return this.panelId !== data.panelId;
|
return this.panel.id !== data.panelId;
|
||||||
}
|
}
|
||||||
|
|
||||||
return this.group.model.canDisplayOverlay(
|
return this.group.model.canDisplayOverlay(
|
||||||
@ -114,6 +118,20 @@ export class Tab extends CompositeDisposable implements ITab {
|
|||||||
});
|
});
|
||||||
|
|
||||||
this.addDisposables(
|
this.addDisposables(
|
||||||
|
this._onChanged,
|
||||||
|
this._onDropped,
|
||||||
|
this._onDragStart,
|
||||||
|
dragHandler.onDragStart((event) => {
|
||||||
|
this._onDragStart.fire(event);
|
||||||
|
}),
|
||||||
|
dragHandler,
|
||||||
|
addDisposableListener(this._element, 'mousedown', (event) => {
|
||||||
|
if (event.defaultPrevented) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this._onChanged.fire(event);
|
||||||
|
}),
|
||||||
this.droptarget.onDrop((event) => {
|
this.droptarget.onDrop((event) => {
|
||||||
this._onDropped.fire(event);
|
this._onDropped.fire(event);
|
||||||
}),
|
}),
|
||||||
|
@ -16,13 +16,20 @@ export interface TabDropIndexEvent {
|
|||||||
readonly index: number;
|
readonly index: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface TabDragEvent {
|
||||||
|
readonly nativeEvent: DragEvent;
|
||||||
|
readonly panel?: IDockviewPanel;
|
||||||
|
}
|
||||||
|
|
||||||
export interface ITabsContainer extends IDisposable {
|
export interface ITabsContainer extends IDisposable {
|
||||||
readonly element: HTMLElement;
|
readonly element: HTMLElement;
|
||||||
readonly panels: string[];
|
readonly panels: string[];
|
||||||
readonly size: number;
|
readonly size: number;
|
||||||
|
hidden: boolean;
|
||||||
delete: (id: string) => void;
|
delete: (id: string) => void;
|
||||||
indexOf: (id: string) => number;
|
indexOf: (id: string) => number;
|
||||||
onDrop: Event<TabDropIndexEvent>;
|
onDrop: Event<TabDropIndexEvent>;
|
||||||
|
onDragStart: Event<TabDragEvent>;
|
||||||
setActive: (isGroupActive: boolean) => void;
|
setActive: (isGroupActive: boolean) => void;
|
||||||
setActivePanel: (panel: IDockviewPanel) => void;
|
setActivePanel: (panel: IDockviewPanel) => void;
|
||||||
isActive: (tab: ITab) => boolean;
|
isActive: (tab: ITab) => boolean;
|
||||||
@ -30,7 +37,6 @@ export interface ITabsContainer extends IDisposable {
|
|||||||
openPanel: (panel: IDockviewPanel, index?: number) => void;
|
openPanel: (panel: IDockviewPanel, index?: number) => void;
|
||||||
setRightActionsElement(element: HTMLElement | undefined): void;
|
setRightActionsElement(element: HTMLElement | undefined): void;
|
||||||
setLeftActionsElement(element: HTMLElement | undefined): void;
|
setLeftActionsElement(element: HTMLElement | undefined): void;
|
||||||
hidden: boolean;
|
|
||||||
show(): void;
|
show(): void;
|
||||||
hide(): void;
|
hide(): void;
|
||||||
}
|
}
|
||||||
@ -55,8 +61,11 @@ export class TabsContainer
|
|||||||
private readonly _onDrop = new Emitter<TabDropIndexEvent>();
|
private readonly _onDrop = new Emitter<TabDropIndexEvent>();
|
||||||
readonly onDrop: Event<TabDropIndexEvent> = this._onDrop.event;
|
readonly onDrop: Event<TabDropIndexEvent> = this._onDrop.event;
|
||||||
|
|
||||||
|
private readonly _onDragStart = new Emitter<TabDragEvent>();
|
||||||
|
readonly onDragStart: Event<TabDragEvent> = this._onDragStart.event;
|
||||||
|
|
||||||
get panels(): string[] {
|
get panels(): string[] {
|
||||||
return this.tabs.map((_) => _.value.panelId);
|
return this.tabs.map((_) => _.value.panel.id);
|
||||||
}
|
}
|
||||||
|
|
||||||
get size(): number {
|
get size(): number {
|
||||||
@ -122,7 +131,7 @@ export class TabsContainer
|
|||||||
}
|
}
|
||||||
|
|
||||||
public indexOf(id: string): number {
|
public indexOf(id: string): number {
|
||||||
return this.tabs.findIndex((tab) => tab.value.panelId === id);
|
return this.tabs.findIndex((tab) => tab.value.panel.id === id);
|
||||||
}
|
}
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
@ -131,7 +140,7 @@ export class TabsContainer
|
|||||||
) {
|
) {
|
||||||
super();
|
super();
|
||||||
|
|
||||||
this.addDisposables(this._onDrop);
|
this.addDisposables(this._onDrop, this._onDragStart);
|
||||||
|
|
||||||
this._element = document.createElement('div');
|
this._element = document.createElement('div');
|
||||||
this._element.className = 'tabs-and-actions-container';
|
this._element.className = 'tabs-and-actions-container';
|
||||||
@ -260,7 +269,7 @@ export class TabsContainer
|
|||||||
}
|
}
|
||||||
|
|
||||||
public delete(id: string): void {
|
public delete(id: string): void {
|
||||||
const index = this.tabs.findIndex((tab) => tab.value.panelId === id);
|
const index = this.tabs.findIndex((tab) => tab.value.panel.id === id);
|
||||||
|
|
||||||
const tabToRemove = this.tabs.splice(index, 1)[0];
|
const tabToRemove = this.tabs.splice(index, 1)[0];
|
||||||
|
|
||||||
@ -273,7 +282,7 @@ export class TabsContainer
|
|||||||
|
|
||||||
public setActivePanel(panel: IDockviewPanel): void {
|
public setActivePanel(panel: IDockviewPanel): void {
|
||||||
this.tabs.forEach((tab) => {
|
this.tabs.forEach((tab) => {
|
||||||
const isActivePanel = panel.id === tab.value.panelId;
|
const isActivePanel = panel.id === tab.value.panel.id;
|
||||||
tab.value.setActive(isActivePanel);
|
tab.value.setActive(isActivePanel);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -282,17 +291,20 @@ export class TabsContainer
|
|||||||
panel: IDockviewPanel,
|
panel: IDockviewPanel,
|
||||||
index: number = this.tabs.length
|
index: number = this.tabs.length
|
||||||
): void {
|
): void {
|
||||||
if (this.tabs.find((tab) => tab.value.panelId === panel.id)) {
|
if (this.tabs.find((tab) => tab.value.panel.id === panel.id)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const tabToAdd = new Tab(panel.id, this.accessor, this.group);
|
const tab = new Tab(panel, this.accessor, this.group);
|
||||||
if (!panel.view?.tab) {
|
if (!panel.view?.tab) {
|
||||||
throw new Error('invalid header component');
|
throw new Error('invalid header component');
|
||||||
}
|
}
|
||||||
tabToAdd.setContent(panel.view.tab);
|
tab.setContent(panel.view.tab);
|
||||||
|
|
||||||
const disposable = CompositeDisposable.from(
|
const disposable = new CompositeDisposable(
|
||||||
tabToAdd.onChanged((event) => {
|
tab.onDragStart((event) => {
|
||||||
|
this._onDragStart.fire({ nativeEvent: event, panel });
|
||||||
|
}),
|
||||||
|
tab.onChanged((event) => {
|
||||||
const isFloatingGroupsEnabled =
|
const isFloatingGroupsEnabled =
|
||||||
!this.accessor.options.disableFloatingGroups;
|
!this.accessor.options.disableFloatingGroups;
|
||||||
|
|
||||||
@ -306,10 +318,9 @@ export class TabsContainer
|
|||||||
) {
|
) {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
|
|
||||||
const panel = this.accessor.getGroupPanel(tabToAdd.panelId);
|
const panel = this.accessor.getGroupPanel(tab.panel.id);
|
||||||
|
|
||||||
const { top, left } =
|
const { top, left } = tab.element.getBoundingClientRect();
|
||||||
tabToAdd.element.getBoundingClientRect();
|
|
||||||
const { top: rootTop, left: rootLeft } =
|
const { top: rootTop, left: rootLeft } =
|
||||||
this.accessor.element.getBoundingClientRect();
|
this.accessor.element.getBoundingClientRect();
|
||||||
|
|
||||||
@ -338,15 +349,15 @@ export class TabsContainer
|
|||||||
skipFocus: alreadyFocused,
|
skipFocus: alreadyFocused,
|
||||||
});
|
});
|
||||||
}),
|
}),
|
||||||
tabToAdd.onDrop((event) => {
|
tab.onDrop((event) => {
|
||||||
this._onDrop.fire({
|
this._onDrop.fire({
|
||||||
event: event.nativeEvent,
|
event: event.nativeEvent,
|
||||||
index: this.tabs.findIndex((x) => x.value === tabToAdd),
|
index: this.tabs.findIndex((x) => x.value === tab),
|
||||||
});
|
});
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
|
||||||
const value: IValueDisposable<ITab> = { value: tabToAdd, disposable };
|
const value: IValueDisposable<ITab> = { value: tab, disposable };
|
||||||
|
|
||||||
this.addTab(value, index);
|
this.addTab(value, index);
|
||||||
}
|
}
|
||||||
|
@ -1157,6 +1157,9 @@ export class DockviewComponent
|
|||||||
|
|
||||||
if (!this._groups.has(view.id)) {
|
if (!this._groups.has(view.id)) {
|
||||||
const disposable = new CompositeDisposable(
|
const disposable = new CompositeDisposable(
|
||||||
|
view.model.onDragStart((event) => {
|
||||||
|
this.onDragStart(event);
|
||||||
|
}),
|
||||||
view.model.onMove((event) => {
|
view.model.onMove((event) => {
|
||||||
const { groupId, itemId, target, index } = event;
|
const { groupId, itemId, target, index } = event;
|
||||||
this.moveGroupOrPanel(view, groupId, itemId, target, index);
|
this.moveGroupOrPanel(view, groupId, itemId, target, index);
|
||||||
|
@ -13,6 +13,7 @@ import {
|
|||||||
} from './components/panel/content';
|
} from './components/panel/content';
|
||||||
import {
|
import {
|
||||||
ITabsContainer,
|
ITabsContainer,
|
||||||
|
TabDragEvent,
|
||||||
TabsContainer,
|
TabsContainer,
|
||||||
} from './components/titlebar/tabsContainer';
|
} from './components/titlebar/tabsContainer';
|
||||||
import { DockviewDropTargets, IWatermarkRenderer } from './types';
|
import { DockviewDropTargets, IWatermarkRenderer } from './types';
|
||||||
@ -158,6 +159,9 @@ export class DockviewGroupPanelModel
|
|||||||
private readonly _onDidDrop = new Emitter<GroupviewDropEvent>();
|
private readonly _onDidDrop = new Emitter<GroupviewDropEvent>();
|
||||||
readonly onDidDrop: Event<GroupviewDropEvent> = this._onDidDrop.event;
|
readonly onDidDrop: Event<GroupviewDropEvent> = this._onDidDrop.event;
|
||||||
|
|
||||||
|
private readonly _onDragStart = new Emitter<TabDragEvent>();
|
||||||
|
readonly onDragStart: Event<TabDragEvent> = this._onDragStart.event;
|
||||||
|
|
||||||
private readonly _onDidAddPanel = new Emitter<GroupviewChangeEvent>();
|
private readonly _onDidAddPanel = new Emitter<GroupviewChangeEvent>();
|
||||||
readonly onDidAddPanel: Event<GroupviewChangeEvent> =
|
readonly onDidAddPanel: Event<GroupviewChangeEvent> =
|
||||||
this._onDidAddPanel.event;
|
this._onDidAddPanel.event;
|
||||||
@ -306,6 +310,9 @@ export class DockviewGroupPanelModel
|
|||||||
this.locked = !!options.locked;
|
this.locked = !!options.locked;
|
||||||
|
|
||||||
this.addDisposables(
|
this.addDisposables(
|
||||||
|
this.tabsContainer.onDragStart((event) => {
|
||||||
|
this._onDragStart.fire(event);
|
||||||
|
}),
|
||||||
this.tabsContainer.onDrop((event) => {
|
this.tabsContainer.onDrop((event) => {
|
||||||
this.handleDropEvent(event.event, 'center', event.index);
|
this.handleDropEvent(event.event, 'center', event.index);
|
||||||
}),
|
}),
|
||||||
|
@ -23,10 +23,6 @@ export class CompositeDisposable {
|
|||||||
return this._isDisposed;
|
return this._isDisposed;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static from(...args: IDisposable[]): CompositeDisposable {
|
|
||||||
return new CompositeDisposable(...args);
|
|
||||||
}
|
|
||||||
|
|
||||||
constructor(...args: IDisposable[]) {
|
constructor(...args: IDisposable[]) {
|
||||||
this._disposables = args;
|
this._disposables = args;
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user