mirror of
https://github.com/mathuo/dockview
synced 2025-02-02 06:25:44 +00:00
feat: experimental work
This commit is contained in:
parent
25489bf48e
commit
97e8a95c2b
@ -679,6 +679,239 @@ describe('dockviewComponent', () => {
|
||||
expect(viewQuery.length).toBe(1);
|
||||
});
|
||||
|
||||
describe('serialization', () => {
|
||||
test('reuseExistingPanels true', () => {
|
||||
const parts: PanelContentPartTest[] = [];
|
||||
|
||||
dockview = new DockviewComponent(container, {
|
||||
createComponent(options) {
|
||||
switch (options.name) {
|
||||
case 'default':
|
||||
const part = new PanelContentPartTest(
|
||||
options.id,
|
||||
options.name
|
||||
);
|
||||
parts.push(part);
|
||||
return part;
|
||||
default:
|
||||
throw new Error(`unsupported`);
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
dockview.layout(1000, 1000);
|
||||
|
||||
dockview.addPanel({ id: 'panel1', component: 'default' });
|
||||
dockview.addPanel({ id: 'panel2', component: 'default' });
|
||||
dockview.addPanel({ id: 'panel7', component: 'default' });
|
||||
|
||||
expect(parts.length).toBe(3);
|
||||
|
||||
expect(parts.map((part) => part.isDisposed)).toEqual([
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
]);
|
||||
|
||||
dockview.fromJSON(
|
||||
{
|
||||
activeGroup: 'group-1',
|
||||
grid: {
|
||||
root: {
|
||||
type: 'branch',
|
||||
data: [
|
||||
{
|
||||
type: 'leaf',
|
||||
data: {
|
||||
views: ['panel1'],
|
||||
id: 'group-1',
|
||||
activeView: 'panel1',
|
||||
},
|
||||
size: 500,
|
||||
},
|
||||
{
|
||||
type: 'branch',
|
||||
data: [
|
||||
{
|
||||
type: 'leaf',
|
||||
data: {
|
||||
views: ['panel2', 'panel3'],
|
||||
id: 'group-2',
|
||||
},
|
||||
size: 500,
|
||||
},
|
||||
{
|
||||
type: 'leaf',
|
||||
data: {
|
||||
views: ['panel4'],
|
||||
id: 'group-3',
|
||||
},
|
||||
size: 500,
|
||||
},
|
||||
],
|
||||
size: 500,
|
||||
},
|
||||
],
|
||||
size: 1000,
|
||||
},
|
||||
height: 1000,
|
||||
width: 1000,
|
||||
orientation: Orientation.VERTICAL,
|
||||
},
|
||||
panels: {
|
||||
panel1: {
|
||||
id: 'panel1',
|
||||
contentComponent: 'default',
|
||||
tabComponent: 'tab-default',
|
||||
title: 'panel1',
|
||||
},
|
||||
panel2: {
|
||||
id: 'panel2',
|
||||
contentComponent: 'default',
|
||||
title: 'panel2',
|
||||
},
|
||||
panel3: {
|
||||
id: 'panel3',
|
||||
contentComponent: 'default',
|
||||
title: 'panel3',
|
||||
renderer: 'onlyWhenVisible',
|
||||
},
|
||||
panel4: {
|
||||
id: 'panel4',
|
||||
contentComponent: 'default',
|
||||
title: 'panel4',
|
||||
renderer: 'always',
|
||||
},
|
||||
},
|
||||
},
|
||||
{ reuseExistingPanels: true }
|
||||
);
|
||||
|
||||
expect(parts.map((part) => part.isDisposed)).toEqual([
|
||||
false,
|
||||
false,
|
||||
true,
|
||||
false,
|
||||
false,
|
||||
]);
|
||||
});
|
||||
|
||||
test('reuseExistingPanels false', () => {
|
||||
const parts: PanelContentPartTest[] = [];
|
||||
|
||||
dockview = new DockviewComponent(container, {
|
||||
createComponent(options) {
|
||||
switch (options.name) {
|
||||
case 'default':
|
||||
const part = new PanelContentPartTest(
|
||||
options.id,
|
||||
options.name
|
||||
);
|
||||
parts.push(part);
|
||||
return part;
|
||||
default:
|
||||
throw new Error(`unsupported`);
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
dockview.layout(1000, 1000);
|
||||
|
||||
dockview.addPanel({ id: 'panel1', component: 'default' });
|
||||
dockview.addPanel({ id: 'panel2', component: 'default' });
|
||||
dockview.addPanel({ id: 'panel7', component: 'default' });
|
||||
|
||||
expect(parts.length).toBe(3);
|
||||
|
||||
expect(parts.map((part) => part.isDisposed)).toEqual([
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
]);
|
||||
|
||||
dockview.fromJSON({
|
||||
activeGroup: 'group-1',
|
||||
grid: {
|
||||
root: {
|
||||
type: 'branch',
|
||||
data: [
|
||||
{
|
||||
type: 'leaf',
|
||||
data: {
|
||||
views: ['panel1'],
|
||||
id: 'group-1',
|
||||
activeView: 'panel1',
|
||||
},
|
||||
size: 500,
|
||||
},
|
||||
{
|
||||
type: 'branch',
|
||||
data: [
|
||||
{
|
||||
type: 'leaf',
|
||||
data: {
|
||||
views: ['panel2', 'panel3'],
|
||||
id: 'group-2',
|
||||
},
|
||||
size: 500,
|
||||
},
|
||||
{
|
||||
type: 'leaf',
|
||||
data: {
|
||||
views: ['panel4'],
|
||||
id: 'group-3',
|
||||
},
|
||||
size: 500,
|
||||
},
|
||||
],
|
||||
size: 500,
|
||||
},
|
||||
],
|
||||
size: 1000,
|
||||
},
|
||||
height: 1000,
|
||||
width: 1000,
|
||||
orientation: Orientation.VERTICAL,
|
||||
},
|
||||
panels: {
|
||||
panel1: {
|
||||
id: 'panel1',
|
||||
contentComponent: 'default',
|
||||
tabComponent: 'tab-default',
|
||||
title: 'panel1',
|
||||
},
|
||||
panel2: {
|
||||
id: 'panel2',
|
||||
contentComponent: 'default',
|
||||
title: 'panel2',
|
||||
},
|
||||
panel3: {
|
||||
id: 'panel3',
|
||||
contentComponent: 'default',
|
||||
title: 'panel3',
|
||||
renderer: 'onlyWhenVisible',
|
||||
},
|
||||
panel4: {
|
||||
id: 'panel4',
|
||||
contentComponent: 'default',
|
||||
title: 'panel4',
|
||||
renderer: 'always',
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
expect(parts.map((part) => part.isDisposed)).toEqual([
|
||||
true,
|
||||
true,
|
||||
true,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
]);
|
||||
});
|
||||
});
|
||||
|
||||
test('serialization', () => {
|
||||
dockview.layout(1000, 1000);
|
||||
|
||||
|
@ -209,6 +209,10 @@ export class TestPanel implements IDockviewPanel {
|
||||
});
|
||||
}
|
||||
|
||||
updateFromStateModel(state: GroupviewPanelState): void {
|
||||
//
|
||||
}
|
||||
|
||||
init(params: IGroupPanelInitParameters) {
|
||||
this._params = params;
|
||||
}
|
||||
|
@ -854,8 +854,11 @@ export class DockviewApi implements CommonApi<SerializedDockview> {
|
||||
/**
|
||||
* Create a component from a serialized object.
|
||||
*/
|
||||
fromJSON(data: SerializedDockview): void {
|
||||
this.component.fromJSON(data);
|
||||
fromJSON(
|
||||
data: SerializedDockview,
|
||||
options?: { reuseExistingPanels: boolean }
|
||||
): void {
|
||||
this.component.fromJSON(data, options);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -147,6 +147,7 @@ type MoveGroupOrPanelOptions = {
|
||||
position: Position;
|
||||
index?: number;
|
||||
};
|
||||
keepEmptyGroups?: boolean;
|
||||
};
|
||||
|
||||
export interface FloatingGroupOptions {
|
||||
@ -219,6 +220,7 @@ export interface IDockviewComponent extends IBaseGrid<DockviewGroupPanel> {
|
||||
onWillClose?: (event: { id: string; window: Window }) => void;
|
||||
}
|
||||
): Promise<boolean>;
|
||||
fromJSON(data: any, options?: { reuseExistingPanels: boolean }): void;
|
||||
}
|
||||
|
||||
export class DockviewComponent
|
||||
@ -381,17 +383,17 @@ export class DockviewComponent
|
||||
this.updateWatermark();
|
||||
}),
|
||||
this.onDidAdd((event) => {
|
||||
if (!this._moving) {
|
||||
if (!this._isEventSuppressionEnabled) {
|
||||
this._onDidAddGroup.fire(event);
|
||||
}
|
||||
}),
|
||||
this.onDidRemove((event) => {
|
||||
if (!this._moving) {
|
||||
if (!this._isEventSuppressionEnabled) {
|
||||
this._onDidRemoveGroup.fire(event);
|
||||
}
|
||||
}),
|
||||
this.onDidActiveChange((event) => {
|
||||
if (!this._moving) {
|
||||
if (!this._isEventSuppressionEnabled) {
|
||||
this._onDidActiveGroupChange.fire(event);
|
||||
}
|
||||
}),
|
||||
@ -675,13 +677,13 @@ export class DockviewComponent
|
||||
|
||||
if (!options?.overridePopoutGroup && isGroupAddedToDom) {
|
||||
if (itemToPopout instanceof DockviewPanel) {
|
||||
this.movingLock(() => {
|
||||
this.runWithSuppressedEvents(() => {
|
||||
const panel =
|
||||
referenceGroup.model.removePanel(itemToPopout);
|
||||
group.model.openPanel(panel);
|
||||
});
|
||||
} else {
|
||||
this.movingLock(() =>
|
||||
this.runWithSuppressedEvents(() =>
|
||||
moveGroupWithoutDestroying({
|
||||
from: referenceGroup,
|
||||
to: group,
|
||||
@ -773,7 +775,7 @@ export class DockviewComponent
|
||||
isGroupAddedToDom &&
|
||||
this.getPanel(referenceGroup.id)
|
||||
) {
|
||||
this.movingLock(() =>
|
||||
this.runWithSuppressedEvents(() =>
|
||||
moveGroupWithoutDestroying({
|
||||
from: group,
|
||||
to: referenceGroup,
|
||||
@ -830,7 +832,7 @@ export class DockviewComponent
|
||||
group = this.createGroup();
|
||||
this._onDidAddGroup.fire(group);
|
||||
|
||||
this.movingLock(() =>
|
||||
this.runWithSuppressedEvents(() =>
|
||||
this.removePanel(item, {
|
||||
removeEmptyGroup: true,
|
||||
skipDispose: true,
|
||||
@ -838,7 +840,7 @@ export class DockviewComponent
|
||||
})
|
||||
);
|
||||
|
||||
this.movingLock(() =>
|
||||
this.runWithSuppressedEvents(() =>
|
||||
group.model.openPanel(item, { skipSetGroupActive: true })
|
||||
);
|
||||
} else {
|
||||
@ -857,7 +859,7 @@ export class DockviewComponent
|
||||
|
||||
if (!skip) {
|
||||
if (popoutReferenceGroup) {
|
||||
this.movingLock(() =>
|
||||
this.runWithSuppressedEvents(() =>
|
||||
moveGroupWithoutDestroying({
|
||||
from: item,
|
||||
to: popoutReferenceGroup,
|
||||
@ -955,7 +957,7 @@ export class DockviewComponent
|
||||
const el = group.element.querySelector('.dv-void-container');
|
||||
|
||||
if (!el) {
|
||||
throw new Error('failed to find drag handle');
|
||||
throw new Error('dockview: failed to find drag handle');
|
||||
}
|
||||
|
||||
overlay.setupDrag(<HTMLElement>el, {
|
||||
@ -1051,7 +1053,7 @@ export class DockviewComponent
|
||||
case 'right':
|
||||
return this.createGroupAtLocation([this.gridview.length]); // insert into last position
|
||||
default:
|
||||
throw new Error(`unsupported position ${position}`);
|
||||
throw new Error(`dockview: unsupported position ${position}`);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1219,17 +1221,62 @@ export class DockviewComponent
|
||||
return result;
|
||||
}
|
||||
|
||||
fromJSON(data: SerializedDockview): void {
|
||||
fromJSON(
|
||||
data: SerializedDockview,
|
||||
options?: { reuseExistingPanels: boolean }
|
||||
): void {
|
||||
const existingPanels = new Map<string, IDockviewPanel>();
|
||||
|
||||
let tempGroup: DockviewGroupPanel | undefined;
|
||||
|
||||
if (options?.reuseExistingPanels) {
|
||||
/**
|
||||
* What are we doing here?
|
||||
*
|
||||
* 1. Create a temporary group to hold any panels that currently exist and that also exist in the new layout
|
||||
* 2. Remove that temporary group from the group mapping so that it doesn't get cleared when we clear the layout
|
||||
*/
|
||||
|
||||
tempGroup = this.createGroup();
|
||||
this._groups.delete(tempGroup.api.id);
|
||||
|
||||
const newPanels = Object.keys(data.panels);
|
||||
|
||||
for (const panel of this.panels) {
|
||||
if (newPanels.includes(panel.api.id)) {
|
||||
existingPanels.set(panel.api.id, panel);
|
||||
}
|
||||
}
|
||||
|
||||
this.runWithSuppressedEvents(() => {
|
||||
Array.from(existingPanels.values()).forEach((panel) => {
|
||||
this.moveGroupOrPanel({
|
||||
from: {
|
||||
groupId: panel.api.group.api.id,
|
||||
panelId: panel.api.id,
|
||||
},
|
||||
to: {
|
||||
group: tempGroup!,
|
||||
position: 'center',
|
||||
},
|
||||
keepEmptyGroups: true,
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
this.clear();
|
||||
|
||||
if (typeof data !== 'object' || data === null) {
|
||||
throw new Error('serialized layout must be a non-null object');
|
||||
throw new Error(
|
||||
'dockview: serialized layout must be a non-null object'
|
||||
);
|
||||
}
|
||||
|
||||
const { grid, panels, activeGroup } = data;
|
||||
|
||||
if (grid.root.type !== 'branch' || !Array.isArray(grid.root.data)) {
|
||||
throw new Error('root must be of type branch');
|
||||
throw new Error('dockview: root must be of type branch');
|
||||
}
|
||||
|
||||
try {
|
||||
@ -1243,7 +1290,9 @@ export class DockviewComponent
|
||||
const { id, locked, hideHeader, views, activeView } = data;
|
||||
|
||||
if (typeof id !== 'string') {
|
||||
throw new Error('group id must be of type string');
|
||||
throw new Error(
|
||||
'dockview: group id must be of type string'
|
||||
);
|
||||
}
|
||||
|
||||
const group = this.createGroup({
|
||||
@ -1260,11 +1309,23 @@ export class DockviewComponent
|
||||
* In running this section first we avoid firing lots of 'add' events in the event of a failure
|
||||
* due to a corruption of input data.
|
||||
*/
|
||||
const panel = this._deserializer.fromJSON(
|
||||
panels[child],
|
||||
group
|
||||
);
|
||||
createdPanels.push(panel);
|
||||
|
||||
const existingPanel = existingPanels.get(child);
|
||||
|
||||
if (tempGroup && existingPanel) {
|
||||
this.runWithSuppressedEvents(() => {
|
||||
tempGroup!.model.removePanel(existingPanel);
|
||||
});
|
||||
|
||||
createdPanels.push(existingPanel);
|
||||
existingPanel.updateFromStateModel(panels[child]);
|
||||
} else {
|
||||
const panel = this._deserializer.fromJSON(
|
||||
panels[child],
|
||||
group
|
||||
);
|
||||
createdPanels.push(panel);
|
||||
}
|
||||
}
|
||||
|
||||
this._onDidAddGroup.fire(group);
|
||||
@ -1276,10 +1337,21 @@ export class DockviewComponent
|
||||
typeof activeView === 'string' &&
|
||||
activeView === panel.id;
|
||||
|
||||
group.model.openPanel(panel, {
|
||||
skipSetActive: !isActive,
|
||||
skipSetGroupActive: true,
|
||||
});
|
||||
const hasExisting = existingPanels.has(panel.api.id);
|
||||
|
||||
if (hasExisting) {
|
||||
this.runWithSuppressedEvents(() => {
|
||||
group.model.openPanel(panel, {
|
||||
skipSetActive: !isActive,
|
||||
skipSetGroupActive: true,
|
||||
});
|
||||
});
|
||||
} else {
|
||||
group.model.openPanel(panel, {
|
||||
skipSetActive: !isActive,
|
||||
skipSetGroupActive: true,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
if (!group.activePanel && group.panels.length > 0) {
|
||||
@ -1426,14 +1498,16 @@ export class DockviewComponent
|
||||
options: AddPanelOptions<T>
|
||||
): DockviewPanel {
|
||||
if (this.panels.find((_) => _.id === options.id)) {
|
||||
throw new Error(`panel with id ${options.id} already exists`);
|
||||
throw new Error(
|
||||
`dockview: panel with id ${options.id} already exists`
|
||||
);
|
||||
}
|
||||
|
||||
let referenceGroup: DockviewGroupPanel | undefined;
|
||||
|
||||
if (options.position && options.floating) {
|
||||
throw new Error(
|
||||
'you can only provide one of: position, floating as arguments to .addPanel(...)'
|
||||
'dockview: you can only provide one of: position, floating as arguments to .addPanel(...)'
|
||||
);
|
||||
}
|
||||
|
||||
@ -1454,7 +1528,7 @@ export class DockviewComponent
|
||||
|
||||
if (!referencePanel) {
|
||||
throw new Error(
|
||||
`referencePanel '${options.position.referencePanel}' does not exist`
|
||||
`dockview: referencePanel '${options.position.referencePanel}' does not exist`
|
||||
);
|
||||
}
|
||||
|
||||
@ -1469,7 +1543,7 @@ export class DockviewComponent
|
||||
|
||||
if (!referenceGroup) {
|
||||
throw new Error(
|
||||
`referenceGroup '${options.position.referenceGroup}' does not exist`
|
||||
`dockview: referenceGroup '${options.position.referenceGroup}' does not exist`
|
||||
);
|
||||
}
|
||||
} else {
|
||||
@ -1634,7 +1708,7 @@ export class DockviewComponent
|
||||
|
||||
if (!group) {
|
||||
throw new Error(
|
||||
`cannot remove panel ${panel.id}. it's missing a group.`
|
||||
`dockview: cannot remove panel ${panel.id}. it's missing a group.`
|
||||
);
|
||||
}
|
||||
|
||||
@ -1700,7 +1774,7 @@ export class DockviewComponent
|
||||
|
||||
if (!referencePanel) {
|
||||
throw new Error(
|
||||
`reference panel ${options.referencePanel} does not exist`
|
||||
`dockview: reference panel ${options.referencePanel} does not exist`
|
||||
);
|
||||
}
|
||||
|
||||
@ -1708,7 +1782,7 @@ export class DockviewComponent
|
||||
|
||||
if (!referenceGroup) {
|
||||
throw new Error(
|
||||
`reference group for reference panel ${options.referencePanel} does not exist`
|
||||
`dockview: reference group for reference panel ${options.referencePanel} does not exist`
|
||||
);
|
||||
}
|
||||
} else if (isGroupOptionsWithGroup(options)) {
|
||||
@ -1719,7 +1793,7 @@ export class DockviewComponent
|
||||
|
||||
if (!referenceGroup) {
|
||||
throw new Error(
|
||||
`reference group ${options.referenceGroup} does not exist`
|
||||
`dockview: reference group ${options.referenceGroup} does not exist`
|
||||
);
|
||||
}
|
||||
} else {
|
||||
@ -1832,7 +1906,7 @@ export class DockviewComponent
|
||||
return floatingGroup.group;
|
||||
}
|
||||
|
||||
throw new Error('failed to find floating group');
|
||||
throw new Error('dockview: failed to find floating group');
|
||||
}
|
||||
|
||||
if (group.api.location.type === 'popout') {
|
||||
@ -1878,7 +1952,7 @@ export class DockviewComponent
|
||||
return selectedGroup.popoutGroup;
|
||||
}
|
||||
|
||||
throw new Error('failed to find popout group');
|
||||
throw new Error('dockview: failed to find popout group');
|
||||
}
|
||||
|
||||
const re = super.doRemoveGroup(group, options);
|
||||
@ -1892,16 +1966,21 @@ export class DockviewComponent
|
||||
return re;
|
||||
}
|
||||
|
||||
private _moving = false;
|
||||
private _isEventSuppressionEnabled = false;
|
||||
|
||||
movingLock<T>(func: () => T): T {
|
||||
const isMoving = this._moving;
|
||||
/**
|
||||
* Code that runs within the provided function will not cause any events to fire. This is useful if you want
|
||||
* to move things around as an intermediate step without raises any associated events
|
||||
*/
|
||||
runWithSuppressedEvents<T>(func: () => T): T {
|
||||
const isMoving = this._isEventSuppressionEnabled;
|
||||
|
||||
try {
|
||||
this._moving = true;
|
||||
this._isEventSuppressionEnabled = true;
|
||||
return func();
|
||||
} finally {
|
||||
this._moving = isMoving;
|
||||
// return to the original state which isn't necessarily false since calls may be nested
|
||||
this._isEventSuppressionEnabled = isMoving;
|
||||
}
|
||||
}
|
||||
|
||||
@ -1917,7 +1996,9 @@ export class DockviewComponent
|
||||
: undefined;
|
||||
|
||||
if (!sourceGroup) {
|
||||
throw new Error(`Failed to find group id ${sourceGroupId}`);
|
||||
throw new Error(
|
||||
`dockview: Failed to find group id ${sourceGroupId}`
|
||||
);
|
||||
}
|
||||
|
||||
if (sourceItemId === undefined) {
|
||||
@ -1940,24 +2021,24 @@ export class DockviewComponent
|
||||
* Dropping a panel within another group
|
||||
*/
|
||||
|
||||
const removedPanel: IDockviewPanel | undefined = this.movingLock(
|
||||
() =>
|
||||
const removedPanel: IDockviewPanel | undefined =
|
||||
this.runWithSuppressedEvents(() =>
|
||||
sourceGroup.model.removePanel(sourceItemId, {
|
||||
skipSetActive: false,
|
||||
skipSetActiveGroup: true,
|
||||
})
|
||||
);
|
||||
);
|
||||
|
||||
if (!removedPanel) {
|
||||
throw new Error(`No panel with id ${sourceItemId}`);
|
||||
throw new Error(`dockview: No panel with id ${sourceItemId}`);
|
||||
}
|
||||
|
||||
if (sourceGroup.model.size === 0) {
|
||||
if (!options.keepEmptyGroups && sourceGroup.model.size === 0) {
|
||||
// remove the group and do not set a new group as active
|
||||
this.doRemoveGroup(sourceGroup, { skipActive: true });
|
||||
}
|
||||
|
||||
this.movingLock(() =>
|
||||
this.runWithSuppressedEvents(() =>
|
||||
destinationGroup.model.openPanel(removedPanel, {
|
||||
index: destinationIndex,
|
||||
skipSetGroupActive: true,
|
||||
@ -2028,7 +2109,7 @@ export class DockviewComponent
|
||||
)!;
|
||||
|
||||
const removedPanel: IDockviewPanel | undefined =
|
||||
this.movingLock(() =>
|
||||
this.runWithSuppressedEvents(() =>
|
||||
popoutGroup.popoutGroup.model.removePanel(
|
||||
popoutGroup.popoutGroup.panels[0],
|
||||
{
|
||||
@ -2041,7 +2122,7 @@ export class DockviewComponent
|
||||
this.doRemoveGroup(sourceGroup, { skipActive: true });
|
||||
|
||||
const newGroup = this.createGroupAtLocation(targetLocation);
|
||||
this.movingLock(() =>
|
||||
this.runWithSuppressedEvents(() =>
|
||||
newGroup.model.openPanel(removedPanel, {
|
||||
skipSetActive: true,
|
||||
})
|
||||
@ -2056,7 +2137,7 @@ export class DockviewComponent
|
||||
}
|
||||
|
||||
// source group will become empty so delete the group
|
||||
const targetGroup = this.movingLock(() =>
|
||||
const targetGroup = this.runWithSuppressedEvents(() =>
|
||||
this.doRemoveGroup(sourceGroup, {
|
||||
skipActive: true,
|
||||
skipDispose: true,
|
||||
@ -2073,7 +2154,9 @@ export class DockviewComponent
|
||||
updatedReferenceLocation,
|
||||
destinationTarget
|
||||
);
|
||||
this.movingLock(() => this.doAddGroup(targetGroup, location));
|
||||
this.runWithSuppressedEvents(() =>
|
||||
this.doAddGroup(targetGroup, location)
|
||||
);
|
||||
this.doSetGroupAndPanelActive(targetGroup);
|
||||
|
||||
this._onDidMovePanel.fire({
|
||||
@ -2086,7 +2169,7 @@ export class DockviewComponent
|
||||
* create a new group, add the panels to that new group and add the new group in an appropiate position
|
||||
*/
|
||||
const removedPanel: IDockviewPanel | undefined =
|
||||
this.movingLock(() =>
|
||||
this.runWithSuppressedEvents(() =>
|
||||
sourceGroup.model.removePanel(sourceItemId, {
|
||||
skipSetActive: false,
|
||||
skipSetActiveGroup: true,
|
||||
@ -2094,7 +2177,9 @@ export class DockviewComponent
|
||||
);
|
||||
|
||||
if (!removedPanel) {
|
||||
throw new Error(`No panel with id ${sourceItemId}`);
|
||||
throw new Error(
|
||||
`dockview: No panel with id ${sourceItemId}`
|
||||
);
|
||||
}
|
||||
|
||||
const dropLocation = getRelativeLocation(
|
||||
@ -2104,7 +2189,7 @@ export class DockviewComponent
|
||||
);
|
||||
|
||||
const group = this.createGroupAtLocation(dropLocation);
|
||||
this.movingLock(() =>
|
||||
this.runWithSuppressedEvents(() =>
|
||||
group.model.openPanel(removedPanel, {
|
||||
skipSetGroupActive: true,
|
||||
})
|
||||
@ -2127,7 +2212,7 @@ export class DockviewComponent
|
||||
if (target === 'center') {
|
||||
const activePanel = from.activePanel;
|
||||
|
||||
const panels = this.movingLock(() =>
|
||||
const panels = this.runWithSuppressedEvents(() =>
|
||||
[...from.panels].map((p) =>
|
||||
from.model.removePanel(p.id, {
|
||||
skipSetActive: true,
|
||||
@ -2139,7 +2224,7 @@ export class DockviewComponent
|
||||
this.doRemoveGroup(from, { skipActive: true });
|
||||
}
|
||||
|
||||
this.movingLock(() => {
|
||||
this.runWithSuppressedEvents(() => {
|
||||
for (const panel of panels) {
|
||||
to.model.openPanel(panel, {
|
||||
skipSetActive: panel !== activePanel,
|
||||
@ -2159,7 +2244,9 @@ export class DockviewComponent
|
||||
(x) => x.group === from
|
||||
);
|
||||
if (!selectedFloatingGroup) {
|
||||
throw new Error('failed to find floating group');
|
||||
throw new Error(
|
||||
'dockview: failed to find floating group'
|
||||
);
|
||||
}
|
||||
selectedFloatingGroup.dispose();
|
||||
break;
|
||||
@ -2169,7 +2256,9 @@ export class DockviewComponent
|
||||
(x) => x.popoutGroup === from
|
||||
);
|
||||
if (!selectedPopoutGroup) {
|
||||
throw new Error('failed to find popout group');
|
||||
throw new Error(
|
||||
'dockview: failed to find popout group'
|
||||
);
|
||||
}
|
||||
selectedPopoutGroup.disposable.dispose();
|
||||
}
|
||||
@ -2213,7 +2302,7 @@ export class DockviewComponent
|
||||
const activePanel = this.activePanel;
|
||||
|
||||
if (
|
||||
!this._moving &&
|
||||
!this._isEventSuppressionEnabled &&
|
||||
activePanel !== this._onDidActivePanelChange.value
|
||||
) {
|
||||
this._onDidActivePanelChange.fire(activePanel);
|
||||
@ -2234,7 +2323,7 @@ export class DockviewComponent
|
||||
}
|
||||
|
||||
if (
|
||||
!this._moving &&
|
||||
!this._isEventSuppressionEnabled &&
|
||||
activePanel !== this._onDidActivePanelChange.value
|
||||
) {
|
||||
this._onDidActivePanelChange.fire(activePanel);
|
||||
@ -2311,19 +2400,19 @@ export class DockviewComponent
|
||||
this._onUnhandledDragOverEvent.fire(event);
|
||||
}),
|
||||
view.model.onDidAddPanel((event) => {
|
||||
if (this._moving) {
|
||||
if (this._isEventSuppressionEnabled) {
|
||||
return;
|
||||
}
|
||||
this._onDidAddPanel.fire(event.panel);
|
||||
}),
|
||||
view.model.onDidRemovePanel((event) => {
|
||||
if (this._moving) {
|
||||
if (this._isEventSuppressionEnabled) {
|
||||
return;
|
||||
}
|
||||
this._onDidRemovePanel.fire(event.panel);
|
||||
}),
|
||||
view.model.onDidActivePanelChange((event) => {
|
||||
if (this._moving) {
|
||||
if (this._isEventSuppressionEnabled) {
|
||||
return;
|
||||
}
|
||||
if (event.panel !== this.activePanel) {
|
||||
|
@ -27,6 +27,7 @@ export interface IDockviewPanel extends IDisposable, IPanel {
|
||||
group: DockviewGroupPanel,
|
||||
options?: { skipSetActive?: boolean }
|
||||
): void;
|
||||
updateFromStateModel(state: GroupviewPanelState): void;
|
||||
init(params: IGroupPanelInitParameters): void;
|
||||
toJSON(): GroupviewPanelState;
|
||||
setTitle(title: string): void;
|
||||
@ -45,10 +46,10 @@ export class DockviewPanel
|
||||
private _title: string | undefined;
|
||||
private _renderer: DockviewPanelRenderer | undefined;
|
||||
|
||||
private readonly _minimumWidth: number | undefined;
|
||||
private readonly _minimumHeight: number | undefined;
|
||||
private readonly _maximumWidth: number | undefined;
|
||||
private readonly _maximumHeight: number | undefined;
|
||||
private _minimumWidth: number | undefined;
|
||||
private _minimumHeight: number | undefined;
|
||||
private _maximumWidth: number | undefined;
|
||||
private _maximumHeight: number | undefined;
|
||||
|
||||
get params(): Parameters | undefined {
|
||||
return this._params;
|
||||
@ -209,6 +210,20 @@ export class DockviewPanel
|
||||
});
|
||||
}
|
||||
|
||||
updateFromStateModel(state: GroupviewPanelState): void {
|
||||
this._maximumHeight = state.maximumHeight;
|
||||
this._minimumHeight = state.minimumHeight;
|
||||
this._maximumWidth = state.maximumWidth;
|
||||
this._minimumWidth = state.minimumWidth;
|
||||
|
||||
this.update({ params: state.params ?? {} });
|
||||
this.setTitle(state.title ?? this.id);
|
||||
this.setRenderer(state.renderer ?? this.accessor.renderer);
|
||||
|
||||
// state.contentComponent;
|
||||
// state.tabComponent;
|
||||
}
|
||||
|
||||
public updateParentGroup(
|
||||
group: DockviewGroupPanel,
|
||||
options?: { skipSetActive?: boolean }
|
||||
|
@ -35,6 +35,12 @@ const components = {
|
||||
const isDebug = React.useContext(DebugContext);
|
||||
const metadata = usePanelApiMetadata(props.api);
|
||||
|
||||
const [firstRender, setFirstRender] = React.useState<string>('');
|
||||
|
||||
React.useEffect(() => {
|
||||
setFirstRender(new Date().toISOString());
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<div
|
||||
style={{
|
||||
@ -59,6 +65,8 @@ const components = {
|
||||
{props.api.title}
|
||||
</span>
|
||||
|
||||
<div>{firstRender}</div>
|
||||
|
||||
{isDebug && (
|
||||
<div style={{ fontSize: '0.8em' }}>
|
||||
<Option
|
||||
|
@ -110,6 +110,22 @@ export const GridActions = (props: {
|
||||
}
|
||||
};
|
||||
|
||||
const onLoad2 = () => {
|
||||
const state = localStorage.getItem('dv-demo-state');
|
||||
if (state) {
|
||||
try {
|
||||
props.api?.fromJSON(JSON.parse(state), {
|
||||
keepExistingPanels: true,
|
||||
});
|
||||
|
||||
setGap(props.api?.gap ?? 0);
|
||||
} catch (err) {
|
||||
console.error('failed to load state', err);
|
||||
localStorage.removeItem('dv-demo-state');
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const onSave = () => {
|
||||
if (props.api) {
|
||||
console.log(props.api.toJSON());
|
||||
@ -192,6 +208,9 @@ export const GridActions = (props: {
|
||||
<button className="text-button" onClick={onLoad}>
|
||||
Load
|
||||
</button>
|
||||
<button className="text-button" onClick={onLoad2}>
|
||||
Load2
|
||||
</button>
|
||||
<button className="text-button" onClick={onSave}>
|
||||
Save
|
||||
</button>
|
||||
|
Loading…
Reference in New Issue
Block a user