Skip to content

Commit a1c0cf9

Browse files
committed
feat: experimental work
1 parent 25489bf commit a1c0cf9

File tree

5 files changed

+165
-48
lines changed

5 files changed

+165
-48
lines changed

packages/dockview-core/src/api/component.api.ts

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -854,8 +854,11 @@ export class DockviewApi implements CommonApi<SerializedDockview> {
854854
/**
855855
* Create a component from a serialized object.
856856
*/
857-
fromJSON(data: SerializedDockview): void {
858-
this.component.fromJSON(data);
857+
fromJSON(
858+
data: SerializedDockview,
859+
options?: { keepExistingPanels: boolean }
860+
): void {
861+
this.component.fromJSON(data, options);
859862
}
860863

861864
/**

packages/dockview-core/src/dockview/dockviewComponent.ts

Lines changed: 114 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -147,6 +147,7 @@ type MoveGroupOrPanelOptions = {
147147
position: Position;
148148
index?: number;
149149
};
150+
keepEmptyGroups?: boolean;
150151
};
151152

152153
export interface FloatingGroupOptions {
@@ -219,6 +220,7 @@ export interface IDockviewComponent extends IBaseGrid<DockviewGroupPanel> {
219220
onWillClose?: (event: { id: string; window: Window }) => void;
220221
}
221222
): Promise<boolean>;
223+
fromJSON(data: any, options?: { keepExistingPanels: boolean }): void;
222224
}
223225

224226
export class DockviewComponent
@@ -381,17 +383,17 @@ export class DockviewComponent
381383
this.updateWatermark();
382384
}),
383385
this.onDidAdd((event) => {
384-
if (!this._moving) {
386+
if (!this._isEventSuppressionEnabled) {
385387
this._onDidAddGroup.fire(event);
386388
}
387389
}),
388390
this.onDidRemove((event) => {
389-
if (!this._moving) {
391+
if (!this._isEventSuppressionEnabled) {
390392
this._onDidRemoveGroup.fire(event);
391393
}
392394
}),
393395
this.onDidActiveChange((event) => {
394-
if (!this._moving) {
396+
if (!this._isEventSuppressionEnabled) {
395397
this._onDidActiveGroupChange.fire(event);
396398
}
397399
}),
@@ -675,13 +677,13 @@ export class DockviewComponent
675677

676678
if (!options?.overridePopoutGroup && isGroupAddedToDom) {
677679
if (itemToPopout instanceof DockviewPanel) {
678-
this.movingLock(() => {
680+
this.runWithSuppressedEvents(() => {
679681
const panel =
680682
referenceGroup.model.removePanel(itemToPopout);
681683
group.model.openPanel(panel);
682684
});
683685
} else {
684-
this.movingLock(() =>
686+
this.runWithSuppressedEvents(() =>
685687
moveGroupWithoutDestroying({
686688
from: referenceGroup,
687689
to: group,
@@ -773,7 +775,7 @@ export class DockviewComponent
773775
isGroupAddedToDom &&
774776
this.getPanel(referenceGroup.id)
775777
) {
776-
this.movingLock(() =>
778+
this.runWithSuppressedEvents(() =>
777779
moveGroupWithoutDestroying({
778780
from: group,
779781
to: referenceGroup,
@@ -830,15 +832,15 @@ export class DockviewComponent
830832
group = this.createGroup();
831833
this._onDidAddGroup.fire(group);
832834

833-
this.movingLock(() =>
835+
this.runWithSuppressedEvents(() =>
834836
this.removePanel(item, {
835837
removeEmptyGroup: true,
836838
skipDispose: true,
837839
skipSetActiveGroup: true,
838840
})
839841
);
840842

841-
this.movingLock(() =>
843+
this.runWithSuppressedEvents(() =>
842844
group.model.openPanel(item, { skipSetGroupActive: true })
843845
);
844846
} else {
@@ -857,7 +859,7 @@ export class DockviewComponent
857859

858860
if (!skip) {
859861
if (popoutReferenceGroup) {
860-
this.movingLock(() =>
862+
this.runWithSuppressedEvents(() =>
861863
moveGroupWithoutDestroying({
862864
from: item,
863865
to: popoutReferenceGroup,
@@ -1219,7 +1221,47 @@ export class DockviewComponent
12191221
return result;
12201222
}
12211223

1222-
fromJSON(data: SerializedDockview): void {
1224+
fromJSON(
1225+
data: SerializedDockview,
1226+
options?: { keepExistingPanels: boolean }
1227+
): void {
1228+
const existingPanels = new Map<string, IDockviewPanel>();
1229+
const tempGroup = this.createGroup();
1230+
this._groups.delete(tempGroup.api.id);
1231+
1232+
if (options?.keepExistingPanels) {
1233+
/**
1234+
* What are we doing here?
1235+
*
1236+
* 1. Create a temporary group to hold any panels that currently exist and that also exist in the new layout
1237+
* 2. Remove that temporary group from the group mapping so that it doesn't get cleared when we clear the layout
1238+
*/
1239+
1240+
const newPanels = Object.keys(data.panels);
1241+
1242+
for (const panel of this.panels) {
1243+
if (newPanels.includes(panel.api.id)) {
1244+
existingPanels.set(panel.api.id, panel);
1245+
}
1246+
}
1247+
1248+
this.runWithSuppressedEvents(() => {
1249+
Array.from(existingPanels.values()).forEach((panel) => {
1250+
this.moveGroupOrPanel({
1251+
from: {
1252+
groupId: panel.api.group.api.id,
1253+
panelId: panel.api.id,
1254+
},
1255+
to: {
1256+
group: tempGroup,
1257+
position: 'center',
1258+
},
1259+
keepEmptyGroups: true,
1260+
});
1261+
});
1262+
});
1263+
}
1264+
12231265
this.clear();
12241266

12251267
if (typeof data !== 'object' || data === null) {
@@ -1260,11 +1302,23 @@ export class DockviewComponent
12601302
* In running this section first we avoid firing lots of 'add' events in the event of a failure
12611303
* due to a corruption of input data.
12621304
*/
1263-
const panel = this._deserializer.fromJSON(
1264-
panels[child],
1265-
group
1266-
);
1267-
createdPanels.push(panel);
1305+
1306+
const existingPanel = existingPanels.get(child);
1307+
1308+
if (existingPanel) {
1309+
this.runWithSuppressedEvents(() => {
1310+
tempGroup.model.removePanel(existingPanel);
1311+
});
1312+
1313+
createdPanels.push(existingPanel);
1314+
existingPanel.updateFromStateModel(panels[child]);
1315+
} else {
1316+
const panel = this._deserializer.fromJSON(
1317+
panels[child],
1318+
group
1319+
);
1320+
createdPanels.push(panel);
1321+
}
12681322
}
12691323

12701324
this._onDidAddGroup.fire(group);
@@ -1276,10 +1330,21 @@ export class DockviewComponent
12761330
typeof activeView === 'string' &&
12771331
activeView === panel.id;
12781332

1279-
group.model.openPanel(panel, {
1280-
skipSetActive: !isActive,
1281-
skipSetGroupActive: true,
1282-
});
1333+
const hasExisting = existingPanels.has(panel.api.id);
1334+
1335+
if (hasExisting) {
1336+
this.runWithSuppressedEvents(() => {
1337+
group.model.openPanel(panel, {
1338+
skipSetActive: !isActive,
1339+
skipSetGroupActive: true,
1340+
});
1341+
});
1342+
} else {
1343+
group.model.openPanel(panel, {
1344+
skipSetActive: !isActive,
1345+
skipSetGroupActive: true,
1346+
});
1347+
}
12831348
}
12841349

12851350
if (!group.activePanel && group.panels.length > 0) {
@@ -1892,16 +1957,21 @@ export class DockviewComponent
18921957
return re;
18931958
}
18941959

1895-
private _moving = false;
1960+
private _isEventSuppressionEnabled = false;
18961961

1897-
movingLock<T>(func: () => T): T {
1898-
const isMoving = this._moving;
1962+
/**
1963+
* Code that runs within the provided function will not cause any events to fire. This is useful if you want
1964+
* to move things around as an intermediate step without raises any associated events
1965+
*/
1966+
runWithSuppressedEvents<T>(func: () => T): T {
1967+
const isMoving = this._isEventSuppressionEnabled;
18991968

19001969
try {
1901-
this._moving = true;
1970+
this._isEventSuppressionEnabled = true;
19021971
return func();
19031972
} finally {
1904-
this._moving = isMoving;
1973+
// return to the original state which isn't necessarily false since calls may be nested
1974+
this._isEventSuppressionEnabled = isMoving;
19051975
}
19061976
}
19071977

@@ -1940,24 +2010,24 @@ export class DockviewComponent
19402010
* Dropping a panel within another group
19412011
*/
19422012

1943-
const removedPanel: IDockviewPanel | undefined = this.movingLock(
1944-
() =>
2013+
const removedPanel: IDockviewPanel | undefined =
2014+
this.runWithSuppressedEvents(() =>
19452015
sourceGroup.model.removePanel(sourceItemId, {
19462016
skipSetActive: false,
19472017
skipSetActiveGroup: true,
19482018
})
1949-
);
2019+
);
19502020

19512021
if (!removedPanel) {
19522022
throw new Error(`No panel with id ${sourceItemId}`);
19532023
}
19542024

1955-
if (sourceGroup.model.size === 0) {
2025+
if (!options.keepEmptyGroups && sourceGroup.model.size === 0) {
19562026
// remove the group and do not set a new group as active
19572027
this.doRemoveGroup(sourceGroup, { skipActive: true });
19582028
}
19592029

1960-
this.movingLock(() =>
2030+
this.runWithSuppressedEvents(() =>
19612031
destinationGroup.model.openPanel(removedPanel, {
19622032
index: destinationIndex,
19632033
skipSetGroupActive: true,
@@ -2028,7 +2098,7 @@ export class DockviewComponent
20282098
)!;
20292099

20302100
const removedPanel: IDockviewPanel | undefined =
2031-
this.movingLock(() =>
2101+
this.runWithSuppressedEvents(() =>
20322102
popoutGroup.popoutGroup.model.removePanel(
20332103
popoutGroup.popoutGroup.panels[0],
20342104
{
@@ -2041,7 +2111,7 @@ export class DockviewComponent
20412111
this.doRemoveGroup(sourceGroup, { skipActive: true });
20422112

20432113
const newGroup = this.createGroupAtLocation(targetLocation);
2044-
this.movingLock(() =>
2114+
this.runWithSuppressedEvents(() =>
20452115
newGroup.model.openPanel(removedPanel, {
20462116
skipSetActive: true,
20472117
})
@@ -2056,7 +2126,7 @@ export class DockviewComponent
20562126
}
20572127

20582128
// source group will become empty so delete the group
2059-
const targetGroup = this.movingLock(() =>
2129+
const targetGroup = this.runWithSuppressedEvents(() =>
20602130
this.doRemoveGroup(sourceGroup, {
20612131
skipActive: true,
20622132
skipDispose: true,
@@ -2073,7 +2143,9 @@ export class DockviewComponent
20732143
updatedReferenceLocation,
20742144
destinationTarget
20752145
);
2076-
this.movingLock(() => this.doAddGroup(targetGroup, location));
2146+
this.runWithSuppressedEvents(() =>
2147+
this.doAddGroup(targetGroup, location)
2148+
);
20772149
this.doSetGroupAndPanelActive(targetGroup);
20782150

20792151
this._onDidMovePanel.fire({
@@ -2086,7 +2158,7 @@ export class DockviewComponent
20862158
* create a new group, add the panels to that new group and add the new group in an appropiate position
20872159
*/
20882160
const removedPanel: IDockviewPanel | undefined =
2089-
this.movingLock(() =>
2161+
this.runWithSuppressedEvents(() =>
20902162
sourceGroup.model.removePanel(sourceItemId, {
20912163
skipSetActive: false,
20922164
skipSetActiveGroup: true,
@@ -2104,7 +2176,7 @@ export class DockviewComponent
21042176
);
21052177

21062178
const group = this.createGroupAtLocation(dropLocation);
2107-
this.movingLock(() =>
2179+
this.runWithSuppressedEvents(() =>
21082180
group.model.openPanel(removedPanel, {
21092181
skipSetGroupActive: true,
21102182
})
@@ -2127,7 +2199,7 @@ export class DockviewComponent
21272199
if (target === 'center') {
21282200
const activePanel = from.activePanel;
21292201

2130-
const panels = this.movingLock(() =>
2202+
const panels = this.runWithSuppressedEvents(() =>
21312203
[...from.panels].map((p) =>
21322204
from.model.removePanel(p.id, {
21332205
skipSetActive: true,
@@ -2139,7 +2211,7 @@ export class DockviewComponent
21392211
this.doRemoveGroup(from, { skipActive: true });
21402212
}
21412213

2142-
this.movingLock(() => {
2214+
this.runWithSuppressedEvents(() => {
21432215
for (const panel of panels) {
21442216
to.model.openPanel(panel, {
21452217
skipSetActive: panel !== activePanel,
@@ -2213,7 +2285,7 @@ export class DockviewComponent
22132285
const activePanel = this.activePanel;
22142286

22152287
if (
2216-
!this._moving &&
2288+
!this._isEventSuppressionEnabled &&
22172289
activePanel !== this._onDidActivePanelChange.value
22182290
) {
22192291
this._onDidActivePanelChange.fire(activePanel);
@@ -2234,7 +2306,7 @@ export class DockviewComponent
22342306
}
22352307

22362308
if (
2237-
!this._moving &&
2309+
!this._isEventSuppressionEnabled &&
22382310
activePanel !== this._onDidActivePanelChange.value
22392311
) {
22402312
this._onDidActivePanelChange.fire(activePanel);
@@ -2311,19 +2383,19 @@ export class DockviewComponent
23112383
this._onUnhandledDragOverEvent.fire(event);
23122384
}),
23132385
view.model.onDidAddPanel((event) => {
2314-
if (this._moving) {
2386+
if (this._isEventSuppressionEnabled) {
23152387
return;
23162388
}
23172389
this._onDidAddPanel.fire(event.panel);
23182390
}),
23192391
view.model.onDidRemovePanel((event) => {
2320-
if (this._moving) {
2392+
if (this._isEventSuppressionEnabled) {
23212393
return;
23222394
}
23232395
this._onDidRemovePanel.fire(event.panel);
23242396
}),
23252397
view.model.onDidActivePanelChange((event) => {
2326-
if (this._moving) {
2398+
if (this._isEventSuppressionEnabled) {
23272399
return;
23282400
}
23292401
if (event.panel !== this.activePanel) {

0 commit comments

Comments
 (0)