From a637ca714b9707db7ef93240298689074a8e2a76 Mon Sep 17 00:00:00 2001 From: mathuo <6710312+mathuo@users.noreply.github.com> Date: Thu, 10 Mar 2022 22:06:55 +0000 Subject: [PATCH 1/2] temp --- .../dockview/src/dnd/abstractDragHandler.ts | 15 ++-- packages/dockview/src/groupview/tab.ts | 84 ++++++++----------- packages/dockview/src/lifecycle.ts | 1 + 3 files changed, 45 insertions(+), 55 deletions(-) diff --git a/packages/dockview/src/dnd/abstractDragHandler.ts b/packages/dockview/src/dnd/abstractDragHandler.ts index 1e45bc6ac..a80bd74ba 100644 --- a/packages/dockview/src/dnd/abstractDragHandler.ts +++ b/packages/dockview/src/dnd/abstractDragHandler.ts @@ -1,14 +1,15 @@ +import { MutableDisposable } from '..'; import { getElementsByTagName } from '../dom'; import { addDisposableListener, Emitter } from '../events'; import { CompositeDisposable, IDisposable } from '../lifecycle'; export abstract class DragHandler extends CompositeDisposable { - private iframes: HTMLElement[] = []; + private readonly disposable = new MutableDisposable(); private readonly _onDragStart = new Emitter(); readonly onDragStart = this._onDragStart.event; - private disposable: IDisposable | undefined; + private iframes: HTMLElement[] = []; constructor(private readonly el: HTMLElement) { super(); @@ -32,8 +33,11 @@ export abstract class DragHandler extends CompositeDisposable { this.el.classList.add('dragged'); setTimeout(() => this.el.classList.remove('dragged'), 0); - this.disposable?.dispose(); - this.disposable = this.getData(); + this.disposable.value = this.getData(); + + if (event.dataTransfer) { + event.dataTransfer.effectAllowed = 'move'; + } }), addDisposableListener(this.el, 'dragend', (ev) => { for (const iframe of this.iframes) { @@ -41,8 +45,7 @@ export abstract class DragHandler extends CompositeDisposable { } this.iframes = []; - this.disposable?.dispose(); - this.disposable = undefined; + this.disposable.dispose(); }) ); } diff --git a/packages/dockview/src/groupview/tab.ts b/packages/dockview/src/groupview/tab.ts index ae90b1a48..34a82a67e 100644 --- a/packages/dockview/src/groupview/tab.ts +++ b/packages/dockview/src/groupview/tab.ts @@ -1,17 +1,18 @@ import { addDisposableListener, Emitter, Event } from '../events'; -import { CompositeDisposable } from '../lifecycle'; +import { CompositeDisposable, IDisposable } from '../lifecycle'; import { getPanelData, LocalSelectionTransfer, PanelTransfer, } from '../dnd/dataTransfer'; -import { getElementsByTagName, toggleClass } from '../dom'; +import { toggleClass } from '../dom'; import { IDockviewComponent } from '../dockview/dockviewComponent'; import { ITabRenderer } from './types'; import { IGroupPanel } from './groupPanel'; import { GroupviewPanel } from './groupviewPanel'; import { DroptargetEvent, Droptarget } from '../dnd/droptarget'; import { DockviewDropTargets } from './dnd'; +import { DragHandler } from '../dnd/abstractDragHandler'; export enum MouseEventKind { CLICK = 'CLICK', @@ -19,15 +20,15 @@ export enum MouseEventKind { } export interface LayoutMouseEvent { - kind: MouseEventKind; - event: MouseEvent; - panel?: IGroupPanel; - tab?: boolean; + readonly kind: MouseEventKind; + readonly event: MouseEvent; + readonly panel?: IGroupPanel; + readonly tab?: boolean; } export interface ITab { - panelId: string; - element: HTMLElement; + readonly panelId: string; + readonly element: HTMLElement; setContent: (element: ITabRenderer) => void; onChanged: Event; onDrop: Event; @@ -35,8 +36,8 @@ export interface ITab { } export class Tab extends CompositeDisposable implements ITab { - private _element: HTMLElement; - private droptarget: Droptarget; + private readonly _element: HTMLElement; + private readonly droptarget: Droptarget; private content?: ITabRenderer; private readonly _onChanged = new Emitter(); @@ -45,19 +46,14 @@ export class Tab extends CompositeDisposable implements ITab { private readonly _onDropped = new Emitter(); readonly onDrop: Event = this._onDropped.event; - private readonly panelTransfer = - LocalSelectionTransfer.getInstance(); - public get element() { return this._element; } - private iframes: HTMLElement[] = []; - constructor( - public panelId: string, - private readonly accessor: IDockviewComponent, - private group: GroupviewPanel + public readonly panelId: string, + accessor: IDockviewComponent, + private readonly group: GroupviewPanel ) { super(); @@ -69,42 +65,32 @@ export class Tab extends CompositeDisposable implements ITab { this._element.draggable = true; this.addDisposables( - addDisposableListener(this._element, 'dragstart', (event) => { - this.iframes = [ - ...getElementsByTagName('iframe'), - ...getElementsByTagName('webview'), - ]; + new (class Handler extends DragHandler { + private readonly panelTransfer = + LocalSelectionTransfer.getInstance(); - for (const iframe of this.iframes) { - iframe.style.pointerEvents = 'none'; + getData(): IDisposable { + this.panelTransfer.setData( + [new PanelTransfer(accessor.id, group.id, panelId)], + PanelTransfer.prototype + ); + + return { + dispose: () => { + this.panelTransfer.clearData( + PanelTransfer.prototype + ); + }, + }; } - this.element.classList.add('dragged'); - setTimeout(() => this.element.classList.remove('dragged'), 0); - - this.panelTransfer.setData( - [ - new PanelTransfer( - this.accessor.id, - this.group.id, - this.panelId - ), - ], - PanelTransfer.prototype - ); - - if (event.dataTransfer) { - event.dataTransfer.effectAllowed = 'move'; + public dispose(): void { + // } - }), - addDisposableListener(this._element, 'dragend', (ev) => { - for (const iframe of this.iframes) { - iframe.style.pointerEvents = 'auto'; - } - this.iframes = []; + })(this._element) + ); - this.panelTransfer.clearData(PanelTransfer.prototype); - }), + this.addDisposables( addDisposableListener(this._element, 'mousedown', (event) => { if (event.defaultPrevented) { return; diff --git a/packages/dockview/src/lifecycle.ts b/packages/dockview/src/lifecycle.ts index 2e6d04540..0486cedff 100644 --- a/packages/dockview/src/lifecycle.ts +++ b/packages/dockview/src/lifecycle.ts @@ -48,6 +48,7 @@ export class MutableDisposable implements IDisposable { public dispose() { if (this._disposable) { this._disposable.dispose(); + this._disposable = Disposable.NONE; } } } From e520a25ef072c778a6100c6812aa35d1d50dabaf Mon Sep 17 00:00:00 2001 From: mathuo <6710312+mathuo@users.noreply.github.com> Date: Fri, 11 Mar 2022 21:20:48 +0000 Subject: [PATCH 2/2] feat: synchronous close panel functions --- .../src/layout-grid/controlCenter.tsx | 12 ++--- .../src/layout-grid/layoutGrid.tsx | 7 --- .../src/panels/welcome/welcome.tsx | 4 +- .../dockview/dockviewGroupPanel.spec.ts | 14 +++++- packages/dockview/src/api/component.api.ts | 10 +--- packages/dockview/src/api/groupPanelApi.ts | 14 +----- .../src/dockview/dockviewComponent.ts | 11 ++-- .../src/dockview/dockviewGroupPanel.ts | 12 ++--- packages/dockview/src/groupview/groupPanel.ts | 1 - packages/dockview/src/groupview/groupview.ts | 50 +++---------------- packages/dockview/src/react/deserializer.ts | 1 + 11 files changed, 36 insertions(+), 100 deletions(-) diff --git a/packages/dockview-demo/src/layout-grid/controlCenter.tsx b/packages/dockview-demo/src/layout-grid/controlCenter.tsx index 3e8ed6cd8..29f329abc 100644 --- a/packages/dockview-demo/src/layout-grid/controlCenter.tsx +++ b/packages/dockview-demo/src/layout-grid/controlCenter.tsx @@ -30,7 +30,7 @@ export const ControlCenter = () => { const panel = api.getPanel(id); if (panel) { - api.setActivePanel(panel); + panel.api.setActive(); return; } api.addPanel({ @@ -76,10 +76,8 @@ export const ControlCenter = () => { const onLoad = async () => { const api = registry.get('dockview'); - const didClose = await api.closeAllGroups(); - if (!didClose) { - return; - } + api.closeAllGroups(); + const data = localStorage.getItem('layout'); if (data) { const jsonData = JSON.parse(data); @@ -102,7 +100,7 @@ export const ControlCenter = () => { const settingsPanel = api.getPanel('settings'); if (settingsPanel) { - api.setActivePanel(settingsPanel); + settingsPanel.api.setActive(); return; } @@ -124,7 +122,7 @@ export const ControlCenter = () => { const onFocusPanel = () => { const api = registry.get('dockview'); const panel = api.getPanel('split_panel'); - api.setActivePanel(panel); + panel.api.setActive(); }; return ( diff --git a/packages/dockview-demo/src/layout-grid/layoutGrid.tsx b/packages/dockview-demo/src/layout-grid/layoutGrid.tsx index 559e5018b..68b64164b 100644 --- a/packages/dockview-demo/src/layout-grid/layoutGrid.tsx +++ b/packages/dockview-demo/src/layout-grid/layoutGrid.tsx @@ -145,13 +145,6 @@ const components: PanelCollection = { }) ); - props.api.interceptOnCloseAction(() => { - if (confirm('close?')) { - return Promise.resolve(true); - } - return Promise.resolve(false); - }); - return () => { disposable.dispose(); }; diff --git a/packages/dockview-demo/src/panels/welcome/welcome.tsx b/packages/dockview-demo/src/panels/welcome/welcome.tsx index 27cffc19a..cfd688f3b 100644 --- a/packages/dockview-demo/src/panels/welcome/welcome.tsx +++ b/packages/dockview-demo/src/panels/welcome/welcome.tsx @@ -6,7 +6,7 @@ export const WelcomePanel = (props: IDockviewPanelProps) => { const onAddSplitview = (event: React.MouseEvent) => { const splitviewPanel = props.containerApi.getPanel('splitview'); if (splitviewPanel) { - props.containerApi.setActivePanel(splitviewPanel); + splitviewPanel.api.setActive(); return; } @@ -20,7 +20,7 @@ export const WelcomePanel = (props: IDockviewPanelProps) => { const onAddGridview = (event: React.MouseEvent) => { const splitviewPanel = props.containerApi.getPanel('gridview'); if (splitviewPanel) { - props.containerApi.setActivePanel(splitviewPanel); + splitviewPanel.api.setActive(); return; } diff --git a/packages/dockview/src/__tests__/dockview/dockviewGroupPanel.spec.ts b/packages/dockview/src/__tests__/dockview/dockviewGroupPanel.spec.ts index 5d5c305f8..43a755a12 100644 --- a/packages/dockview/src/__tests__/dockview/dockviewGroupPanel.spec.ts +++ b/packages/dockview/src/__tests__/dockview/dockviewGroupPanel.spec.ts @@ -1,3 +1,4 @@ +import { DockviewComponent } from '../..'; import { DockviewApi } from '../../api/component.api'; import { DockviewGroupPanel } from '../../dockview/dockviewGroupPanel'; @@ -6,8 +7,12 @@ describe('dockviewGroupPanel', () => { const dockviewApiMock = jest.fn(() => { return {} as any; }); + const accessorMock = jest.fn(() => { + return {} as any; + }); const api = new dockviewApiMock(); - const cut = new DockviewGroupPanel('fake-id', api); + const accessor = new accessorMock(); + const cut = new DockviewGroupPanel('fake-id', accessor, api); let latestTitle: string | undefined = undefined; @@ -32,8 +37,13 @@ describe('dockviewGroupPanel', () => { const dockviewApiMock = jest.fn(() => { return {} as any; }); + const accessorMock = jest.fn(() => { + return {} as any; + }); const api = new dockviewApiMock(); - const cut = new DockviewGroupPanel('fake-id', api); + const accessor = new accessorMock(); + + const cut = new DockviewGroupPanel('fake-id', accessor, api); let latestSuppressClosable: boolean | undefined = undefined; diff --git a/packages/dockview/src/api/component.api.ts b/packages/dockview/src/api/component.api.ts index 5beb0a87b..6e6598211 100644 --- a/packages/dockview/src/api/component.api.ts +++ b/packages/dockview/src/api/component.api.ts @@ -396,10 +396,6 @@ export class DockviewApi implements CommonApi { return this.component.getGroupPanel(id); } - setActivePanel(panel: IGroupPanel): void { - this.component.setActivePanel(panel); - } - layout(width: number, height: number, force = false): void { this.component.layout(width, height, force); } @@ -408,10 +404,6 @@ export class DockviewApi implements CommonApi { return this.component.addPanel(options); } - removePanel(panel: IGroupPanel): void { - this.component.removePanel(panel); - } - addEmptyGroup(options?: AddGroupOptions): void { this.component.addEmptyGroup(options); } @@ -424,7 +416,7 @@ export class DockviewApi implements CommonApi { this.component.moveToPrevious(options); } - closeAllGroups(): Promise { + closeAllGroups(): void { return this.component.closeAllGroups(); } diff --git a/packages/dockview/src/api/groupPanelApi.ts b/packages/dockview/src/api/groupPanelApi.ts index 2dc4a1765..83c91c84b 100644 --- a/packages/dockview/src/api/groupPanelApi.ts +++ b/packages/dockview/src/api/groupPanelApi.ts @@ -21,8 +21,7 @@ export interface DockviewPanelApi readonly isGroupActive: boolean; readonly title: string; readonly suppressClosable: boolean; - close: () => Promise; - interceptOnCloseAction(interceptor: () => Promise): void; + close(): void; setTitle(title: string): void; } @@ -31,7 +30,6 @@ export class DockviewPanelApiImpl implements DockviewPanelApi { private _group: GroupviewPanel | undefined; - private _interceptor: undefined | (() => Promise); readonly _onDidTitleChange = new Emitter(); readonly onDidTitleChange = this._onDidTitleChange.event; @@ -42,10 +40,6 @@ export class DockviewPanelApiImpl readonly _suppressClosableChanged = new Emitter(); readonly suppressClosableChanged = this._suppressClosableChanged.event; - get tryClose(): undefined | (() => Promise) { - return this._interceptor; - } - get title() { return this.panel.title; } @@ -75,17 +69,13 @@ export class DockviewPanelApiImpl this._onDidTitleChange.fire({ title }); } - public close(): Promise { + public close(): void { if (!this.group) { throw new Error(`panel ${this.id} has no group`); } return this.group.model.closePanel(this.panel); } - public interceptOnCloseAction(interceptor: () => Promise) { - this._interceptor = interceptor; - } - public dispose() { super.dispose(); } diff --git a/packages/dockview/src/dockview/dockviewComponent.ts b/packages/dockview/src/dockview/dockviewComponent.ts index 0bc59136e..34e0ab18b 100644 --- a/packages/dockview/src/dockview/dockviewComponent.ts +++ b/packages/dockview/src/dockview/dockviewComponent.ts @@ -103,7 +103,7 @@ export interface IDockviewComponent extends IBaseGrid { // lifecycle addEmptyGroup(options?: AddGroupOptions): void; - closeAllGroups: () => Promise; + closeAllGroups(): void; // events onTabInteractionEvent: Event; onTabContextMenu: Event; @@ -394,16 +394,12 @@ export class DockviewComponent this._onGridEvent.fire({ kind: GroupChangeKind.LAYOUT_FROM_JSON }); } - async closeAllGroups(): Promise { + closeAllGroups(): void { for (const entry of this._groups.entries()) { const [_, group] = entry; - const didCloseAll = await group.value.model.closeAllPanels(); - if (!didCloseAll) { - return false; - } + group.value.model.closeAllPanels(); } - return true; } fireMouseEvent(event: LayoutMouseEvent): void { @@ -736,6 +732,7 @@ export class DockviewComponent const panel: IGroupPanel = new DockviewGroupPanel( options.id, + this, this._api ); panel.init({ diff --git a/packages/dockview/src/dockview/dockviewGroupPanel.ts b/packages/dockview/src/dockview/dockviewGroupPanel.ts index c55c49e3e..c0ddcd33d 100644 --- a/packages/dockview/src/dockview/dockviewGroupPanel.ts +++ b/packages/dockview/src/dockview/dockviewGroupPanel.ts @@ -11,6 +11,7 @@ import { GroupviewPanel } from '../groupview/groupviewPanel'; import { CompositeDisposable, MutableDisposable } from '../lifecycle'; import { Parameters } from '../panel/types'; import { IGroupPanelView } from './defaultGroupPanelView'; +import { DockviewComponent } from './dockviewComponent'; export class DockviewGroupPanel extends CompositeDisposable @@ -45,6 +46,7 @@ export class DockviewGroupPanel constructor( public readonly id: string, + accessor: DockviewComponent, private readonly containerApi: DockviewApi ) { super(); @@ -55,7 +57,7 @@ export class DockviewGroupPanel this.addDisposables( this.api.onActiveChange(() => { - this.containerApi.setActivePanel(this); + accessor.setActivePanel(this); }), this.api.onDidTitleChange((event) => { const title = event.title; @@ -82,14 +84,6 @@ export class DockviewGroupPanel this.api._onFocusEvent.fire(); } - public close(): Promise { - if (this.api.tryClose) { - return this.api.tryClose(); - } - - return Promise.resolve(true); - } - public toJSON(): GroupviewPanelState { return { id: this.id, diff --git a/packages/dockview/src/groupview/groupPanel.ts b/packages/dockview/src/groupview/groupPanel.ts index 9b3179e05..609ac77d0 100644 --- a/packages/dockview/src/groupview/groupPanel.ts +++ b/packages/dockview/src/groupview/groupPanel.ts @@ -29,7 +29,6 @@ export interface IGroupPanel extends IDisposable, IPanel { readonly title: string; readonly suppressClosable: boolean; updateParentGroup(group: GroupviewPanel, isGroupActive: boolean): void; - close?(): Promise; init(params: IGroupPanelInitParameters): void; toJSON(): GroupviewPanelState; update(event: GroupPanelUpdateEvent): void; diff --git a/packages/dockview/src/groupview/groupview.ts b/packages/dockview/src/groupview/groupview.ts index 98afcb6c7..77d01e861 100644 --- a/packages/dockview/src/groupview/groupview.ts +++ b/packages/dockview/src/groupview/groupview.ts @@ -88,8 +88,8 @@ export interface IGroupview extends IDisposable, IGridPanelView { panel: IGroupPanel, options?: { index?: number; skipFocus?: boolean } ): void; - closePanel(panel: IGroupPanel): Promise; - closeAllPanels(): Promise; + closePanel(panel: IGroupPanel): void; + closeAllPanels(): void; containsPanel(panel: IGroupPanel): boolean; removePanel: (panelOrId: IGroupPanel | string) => IGroupPanel; // events @@ -393,57 +393,19 @@ export class Groupview extends CompositeDisposable implements IGroupview { return this._removePanel(panelToRemove); } - public async closeAllPanels() { - const index = this._activePanel - ? this.panels.indexOf(this._activePanel) - : -1; - - if (this._activePanel && index > -1) { - if (this.panels.indexOf(this._activePanel) < 0) { - console.warn('active panel not tracked'); - } - - const canClose = - !this._activePanel?.close || (await this._activePanel.close()); - if (!canClose) { - return false; - } - } - - for (let i = 0; i < this.panels.length; i++) { - if (i === index) { - continue; - } - const panel = this.panels[i]; - this.openPanel(panel); - - if (panel.close) { - const canClose = await panel.close(); - if (!canClose) { - return false; - } - } - } - + public closeAllPanels() { if (this.panels.length > 0) { // take a copy since we will be edting the array as we iterate through const arrPanelCpy = [...this.panels]; - await Promise.all(arrPanelCpy.map((p) => this.doClose(p))); + arrPanelCpy.map((p) => this.doClose(p)); } else { this.accessor.removeGroup(this.parent); } - - return true; } - public closePanel = async (panel: IGroupPanel) => { - if (panel.close && !(await panel.close())) { - return false; - } - + public closePanel(panel: IGroupPanel): void { this.doClose(panel); - return true; - }; + } private doClose(panel: IGroupPanel) { this.accessor.removePanel(panel); diff --git a/packages/dockview/src/react/deserializer.ts b/packages/dockview/src/react/deserializer.ts index f9e5a827b..904f25891 100644 --- a/packages/dockview/src/react/deserializer.ts +++ b/packages/dockview/src/react/deserializer.ts @@ -38,6 +38,7 @@ export class ReactPanelDeserialzier implements IPanelDeserializer { const panel = new DockviewGroupPanel( panelId, + this.layout, new DockviewApi(this.layout) );