dockview-core 8.1.0 → 8.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cjs/api/dockviewPanelApi.d.ts +12 -0
- package/dist/cjs/dockview/dockviewComponent.d.ts +62 -0
- package/dist/cjs/overlay/overlayRenderContainer.d.ts +13 -1
- package/dist/dockview-core.js +482 -102
- package/dist/dockview-core.min.js +2 -2
- package/dist/dockview-core.min.noStyle.js +2 -2
- package/dist/dockview-core.noStyle.js +482 -102
- package/dist/package/main.cjs.js +482 -102
- package/dist/package/main.cjs.min.js +2 -2
- package/dist/package/main.esm.min.mjs +2 -2
- package/dist/package/main.esm.mjs +482 -102
- package/package.json +1 -1
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* dockview-core
|
|
3
|
-
* @version 8.
|
|
3
|
+
* @version 8.2.0
|
|
4
4
|
* @link https://github.com/dockview/dockview
|
|
5
5
|
* @license MIT
|
|
6
6
|
*/
|
|
@@ -10520,7 +10520,11 @@ var DockviewGroupPanelModel = class extends CompositeDisposable {
|
|
|
10520
10520
|
this.panels.forEach((panel) => {
|
|
10521
10521
|
this.rerender(panel);
|
|
10522
10522
|
});
|
|
10523
|
-
if (this._activePanel)
|
|
10523
|
+
if (this._activePanel) {
|
|
10524
|
+
this.contentContainer.renderPanel(this._activePanel, { asActive: true });
|
|
10525
|
+
const { width, height } = this.contentDimensions();
|
|
10526
|
+
this._activePanel.layout(width, height);
|
|
10527
|
+
}
|
|
10524
10528
|
}
|
|
10525
10529
|
get renderContainer() {
|
|
10526
10530
|
var _this$_overwriteRende;
|
|
@@ -11485,7 +11489,7 @@ var DockviewPanelApiImpl = class extends GridviewPanelApiImpl {
|
|
|
11485
11489
|
this._group = value;
|
|
11486
11490
|
this._onDidGroupChange.fire({});
|
|
11487
11491
|
this.setupGroupEventListeners(oldGroup);
|
|
11488
|
-
this.
|
|
11492
|
+
this.fireLocationChange();
|
|
11489
11493
|
}
|
|
11490
11494
|
}
|
|
11491
11495
|
get group() {
|
|
@@ -11561,6 +11565,23 @@ var DockviewPanelApiImpl = class extends GridviewPanelApiImpl {
|
|
|
11561
11565
|
exitMaximized() {
|
|
11562
11566
|
this.group.api.exitMaximized();
|
|
11563
11567
|
}
|
|
11568
|
+
/**
|
|
11569
|
+
* Report that this panel's location may have moved.
|
|
11570
|
+
*
|
|
11571
|
+
* A relocation touches the location more than once - the panel is
|
|
11572
|
+
* reparented into the destination group, then that group is tagged with
|
|
11573
|
+
* the location it ends up at - so the event is coalesced to the end of the
|
|
11574
|
+
* enclosing layout mutation and reports where the panel actually settled.
|
|
11575
|
+
* Firing each signal as it happened surfaced an intermediate `grid`
|
|
11576
|
+
* location the panel was never in, at a point where it was in neither
|
|
11577
|
+
* group's panel list. Outside a mutation this fires straight away.
|
|
11578
|
+
*/
|
|
11579
|
+
fireLocationChange() {
|
|
11580
|
+
this.accessor.deferLocationChange(this, () => {
|
|
11581
|
+
if (this.isDisposed) return;
|
|
11582
|
+
this._onDidLocationChange.fire({ location: this.location });
|
|
11583
|
+
});
|
|
11584
|
+
}
|
|
11564
11585
|
setupGroupEventListeners(previousGroup) {
|
|
11565
11586
|
var _previousGroup$isActi;
|
|
11566
11587
|
let _trackGroupActive = (_previousGroup$isActi = previousGroup === null || previousGroup === void 0 ? void 0 : previousGroup.isActive) !== null && _previousGroup$isActi !== void 0 ? _previousGroup$isActi : false;
|
|
@@ -11569,9 +11590,9 @@ var DockviewPanelApiImpl = class extends GridviewPanelApiImpl {
|
|
|
11569
11590
|
const hasBecomeVisible = event.isVisible && !this.isVisible;
|
|
11570
11591
|
const isActivePanel = this.group.model.isPanelActive(this.panel);
|
|
11571
11592
|
if (hasBecomeHidden || hasBecomeVisible && isActivePanel) this._onDidVisibilityChange.fire(event);
|
|
11572
|
-
}), this.group.api.onDidLocationChange((
|
|
11593
|
+
}), this.group.api.onDidLocationChange(() => {
|
|
11573
11594
|
if (this.group !== this.panel.group) return;
|
|
11574
|
-
this.
|
|
11595
|
+
this.fireLocationChange();
|
|
11575
11596
|
}), this.group.api.onDidActiveChange(() => {
|
|
11576
11597
|
if (this.group !== this.panel.group) return;
|
|
11577
11598
|
if (_trackGroupActive !== this.isGroupActive) {
|
|
@@ -13597,6 +13618,13 @@ var PositionCache = class {
|
|
|
13597
13618
|
});
|
|
13598
13619
|
}
|
|
13599
13620
|
};
|
|
13621
|
+
/**
|
|
13622
|
+
* Placeholder handle marking "a reposition frame has been requested but the
|
|
13623
|
+
* real handle is not known yet". Never passed to `cancelAnimationFrame` in
|
|
13624
|
+
* practice — it is replaced within the same synchronous block — and harmless
|
|
13625
|
+
* if it were, since no frame carries this id.
|
|
13626
|
+
*/
|
|
13627
|
+
const SCHEDULED = -1;
|
|
13600
13628
|
function createFocusableElement() {
|
|
13601
13629
|
const element = document.createElement("div");
|
|
13602
13630
|
element.tabIndex = -1;
|
|
@@ -13609,12 +13637,13 @@ var OverlayRenderContainer = class extends CompositeDisposable {
|
|
|
13609
13637
|
this.accessor = accessor;
|
|
13610
13638
|
this.map = {};
|
|
13611
13639
|
this._disposed = false;
|
|
13640
|
+
this._generation = 0;
|
|
13612
13641
|
this.positionCache = new PositionCache();
|
|
13613
|
-
this.pendingUpdates = /* @__PURE__ */ new Set();
|
|
13614
13642
|
this.addDisposables(Disposable.from(() => {
|
|
13615
13643
|
for (const value of Object.values(this.map)) {
|
|
13616
13644
|
value.disposable.dispose();
|
|
13617
13645
|
value.destroy.dispose();
|
|
13646
|
+
this.cancelPendingUpdate(value);
|
|
13618
13647
|
}
|
|
13619
13648
|
this._disposed = true;
|
|
13620
13649
|
}));
|
|
@@ -13641,11 +13670,24 @@ var OverlayRenderContainer = class extends CompositeDisposable {
|
|
|
13641
13670
|
this.positionCache.invalidate();
|
|
13642
13671
|
(_entry$resize = entry.resize) === null || _entry$resize === void 0 || _entry$resize.call(entry);
|
|
13643
13672
|
}
|
|
13673
|
+
/**
|
|
13674
|
+
* Drop the reposition frame queued for a panel, if any. A queued frame is
|
|
13675
|
+
* bound to the reference container that was current when it was scheduled,
|
|
13676
|
+
* so it must be discarded whenever that container stops being the one the
|
|
13677
|
+
* overlay should track.
|
|
13678
|
+
*/
|
|
13679
|
+
cancelPendingUpdate(entry) {
|
|
13680
|
+
if (entry.pendingUpdate !== void 0) {
|
|
13681
|
+
cancelAnimationFrame(entry.pendingUpdate);
|
|
13682
|
+
entry.pendingUpdate = void 0;
|
|
13683
|
+
}
|
|
13684
|
+
}
|
|
13644
13685
|
detatch(panel) {
|
|
13645
13686
|
if (this.map[panel.api.id]) {
|
|
13646
|
-
const
|
|
13647
|
-
disposable.dispose();
|
|
13648
|
-
destroy.dispose();
|
|
13687
|
+
const entry = this.map[panel.api.id];
|
|
13688
|
+
entry.disposable.dispose();
|
|
13689
|
+
entry.destroy.dispose();
|
|
13690
|
+
this.cancelPendingUpdate(entry);
|
|
13649
13691
|
delete this.map[panel.api.id];
|
|
13650
13692
|
return true;
|
|
13651
13693
|
}
|
|
@@ -13661,22 +13703,73 @@ var OverlayRenderContainer = class extends CompositeDisposable {
|
|
|
13661
13703
|
panel,
|
|
13662
13704
|
disposable: Disposable.NONE,
|
|
13663
13705
|
destroy: Disposable.NONE,
|
|
13664
|
-
element
|
|
13706
|
+
element,
|
|
13707
|
+
retainPreviousGeometry: false,
|
|
13708
|
+
positioned: false,
|
|
13709
|
+
generation: ++this._generation
|
|
13665
13710
|
};
|
|
13666
13711
|
}
|
|
13667
|
-
const
|
|
13712
|
+
const mapEntry = this.map[panel.api.id];
|
|
13713
|
+
/**
|
|
13714
|
+
* A *change* of reference container supersedes the previous `attach`:
|
|
13715
|
+
* take a fresh generation so its `resize` closure can no longer run,
|
|
13716
|
+
* and drop the frame it queued against the old container. During
|
|
13717
|
+
* `fromJSON({ reuseExistingPanels: true })` that old container is a
|
|
13718
|
+
* detached staging group measuring 0x0, so leaving its frame in flight
|
|
13719
|
+
* both wastes the update and delays the reposition against the real one.
|
|
13720
|
+
*
|
|
13721
|
+
* Re-attaching over the *same* container (re-open, active panel change)
|
|
13722
|
+
* deliberately leaves scheduled work alone: `repositionPanelOverlay`
|
|
13723
|
+
* (the auto-hide peek) schedules a frame carrying the sticky
|
|
13724
|
+
* `forceVisible`/`clip` state which `attach` does not re-apply, and a
|
|
13725
|
+
* peeked panel's `api.isVisible` is false — so discarding that frame
|
|
13726
|
+
* leaves `visibilityChanged` to hide the overlay and the peek renders
|
|
13727
|
+
* nothing. A newly created entry already holds a fresh generation, so
|
|
13728
|
+
* the stale closures a `detatch` left behind are fenced off either way.
|
|
13729
|
+
*/
|
|
13730
|
+
if (mapEntry.referenceContainer !== referenceContainer) {
|
|
13731
|
+
mapEntry.generation = ++this._generation;
|
|
13732
|
+
this.cancelPendingUpdate(mapEntry);
|
|
13733
|
+
mapEntry.referenceContainer = referenceContainer;
|
|
13734
|
+
/**
|
|
13735
|
+
* Arm the retain flag only here: it means "a replacement reference
|
|
13736
|
+
* container is awaiting layout", so the 0x0 early-return below
|
|
13737
|
+
* holds the last good box rather than blanking the panel mid-move.
|
|
13738
|
+
* Arming it on every re-attach instead would make a container that
|
|
13739
|
+
* genuinely collapses to zero keep its stale geometry forever.
|
|
13740
|
+
*
|
|
13741
|
+
* Gated on `positioned` because an overlay that has never been
|
|
13742
|
+
* positioned has no left/top/width/height, and `.dv-render-overlay`
|
|
13743
|
+
* defaults to 100%/100% — retaining "previous" geometry there would
|
|
13744
|
+
* pin the content over the whole container.
|
|
13745
|
+
*/
|
|
13746
|
+
mapEntry.retainPreviousGeometry = mapEntry.positioned;
|
|
13747
|
+
}
|
|
13748
|
+
const generation = mapEntry.generation;
|
|
13749
|
+
const focusContainer = mapEntry.element;
|
|
13668
13750
|
const contentElement = panel.view.content.element;
|
|
13669
13751
|
if (contentElement.parentElement !== focusContainer) focusContainer.appendChild(contentElement);
|
|
13670
13752
|
if (focusContainer.parentElement !== this.element) this.element.appendChild(focusContainer);
|
|
13671
13753
|
const resize = () => {
|
|
13672
13754
|
const panelId = panel.api.id;
|
|
13673
|
-
|
|
13674
|
-
|
|
13675
|
-
|
|
13755
|
+
const scheduling = this.map[panelId];
|
|
13756
|
+
if ((scheduling === null || scheduling === void 0 ? void 0 : scheduling.generation) !== generation) return;
|
|
13757
|
+
if (scheduling.pendingUpdate !== void 0) return;
|
|
13758
|
+
/**
|
|
13759
|
+
* Claim the slot *before* scheduling. `requestAnimationFrame` is
|
|
13760
|
+
* shimmed to run inline by some hosts (and by several suites here),
|
|
13761
|
+
* in which case the callback below clears `pendingUpdate` while
|
|
13762
|
+
* this call is still on the stack — assigning the handle afterwards
|
|
13763
|
+
* would resurrect a slot that is already spent and block every
|
|
13764
|
+
* later reposition. The sentinel is replaced by the real handle
|
|
13765
|
+
* only if the frame has not already run.
|
|
13766
|
+
*/
|
|
13767
|
+
scheduling.pendingUpdate = SCHEDULED;
|
|
13768
|
+
const handle = requestAnimationFrame(() => {
|
|
13676
13769
|
var _entry$forceVisible;
|
|
13677
|
-
this.pendingUpdates.delete(panelId);
|
|
13678
13770
|
const entry = this.map[panelId];
|
|
13679
|
-
if (
|
|
13771
|
+
if (entry) entry.pendingUpdate = void 0;
|
|
13772
|
+
if (this.isDisposed || (entry === null || entry === void 0 ? void 0 : entry.generation) !== generation) return;
|
|
13680
13773
|
const forceVisible = (_entry$forceVisible = entry.forceVisible) !== null && _entry$forceVisible !== void 0 ? _entry$forceVisible : false;
|
|
13681
13774
|
const clip = entry.clip;
|
|
13682
13775
|
const box = this.positionCache.getPosition(referenceContainer.element);
|
|
@@ -13685,6 +13778,15 @@ var OverlayRenderContainer = class extends CompositeDisposable {
|
|
|
13685
13778
|
const top = box.top - box2.top;
|
|
13686
13779
|
const width = box.width;
|
|
13687
13780
|
const height = box.height;
|
|
13781
|
+
if (entry.retainPreviousGeometry && (width === 0 || height === 0)) {
|
|
13782
|
+
if (!panel.api.isVisible && !forceVisible) {
|
|
13783
|
+
focusContainer.style.visibility = "hidden";
|
|
13784
|
+
focusContainer.style.pointerEvents = "none";
|
|
13785
|
+
}
|
|
13786
|
+
return;
|
|
13787
|
+
}
|
|
13788
|
+
entry.retainPreviousGeometry = false;
|
|
13789
|
+
entry.positioned = true;
|
|
13688
13790
|
focusContainer.style.left = `${left}px`;
|
|
13689
13791
|
focusContainer.style.top = `${top}px`;
|
|
13690
13792
|
focusContainer.style.width = `${width}px`;
|
|
@@ -13713,11 +13815,30 @@ var OverlayRenderContainer = class extends CompositeDisposable {
|
|
|
13713
13815
|
} else focusContainer.style.clipPath = "";
|
|
13714
13816
|
toggleClass(focusContainer, "dv-render-overlay-float", panel.group.api.location.type === "floating");
|
|
13715
13817
|
});
|
|
13818
|
+
if (scheduling.pendingUpdate === SCHEDULED) scheduling.pendingUpdate = handle;
|
|
13716
13819
|
};
|
|
13717
13820
|
const visibilityChanged = () => {
|
|
13718
13821
|
if (panel.api.isVisible) {
|
|
13822
|
+
var _this$map$panel$api$i;
|
|
13719
13823
|
this.positionCache.invalidate();
|
|
13720
13824
|
resize();
|
|
13825
|
+
/**
|
|
13826
|
+
* Existing geometry is safe to show while its replacement lays
|
|
13827
|
+
* out. `retainPreviousGeometry` is only set when geometry has
|
|
13828
|
+
* actually been written (see `attach`), so this can never
|
|
13829
|
+
* un-hide an overlay whose left/top/width/height are unset —
|
|
13830
|
+
* `.dv-render-overlay` is 100%/100% by default and would
|
|
13831
|
+
* otherwise cover the whole dock.
|
|
13832
|
+
*
|
|
13833
|
+
* The retained geometry is the panel's position in the previous
|
|
13834
|
+
* layout, so restoring a layout that moves the panel does paint
|
|
13835
|
+
* it at stale coordinates until the reposition lands. That is
|
|
13836
|
+
* bounded to the next frame now that a superseded `attach` can
|
|
13837
|
+
* no longer swallow the reposition (see `attach`); showing
|
|
13838
|
+
* stale-but-real geometry for a frame is the deliberate
|
|
13839
|
+
* trade-off against blanking the panel for the whole rebuild.
|
|
13840
|
+
*/
|
|
13841
|
+
if ((_this$map$panel$api$i = this.map[panel.api.id]) === null || _this$map$panel$api$i === void 0 ? void 0 : _this$map$panel$api$i.retainPreviousGeometry) focusContainer.style.visibility = "";
|
|
13721
13842
|
focusContainer.style.pointerEvents = "";
|
|
13722
13843
|
} else {
|
|
13723
13844
|
focusContainer.style.visibility = "hidden";
|
|
@@ -13940,7 +14061,17 @@ var PopoutWindow = class extends CompositeDisposable {
|
|
|
13940
14061
|
window: externalWindow
|
|
13941
14062
|
});
|
|
13942
14063
|
return new Promise((resolve, reject) => {
|
|
13943
|
-
externalWindow.addEventListener("unload", (
|
|
14064
|
+
externalWindow.addEventListener("unload", () => {});
|
|
14065
|
+
/**
|
|
14066
|
+
* `load` is the only event that resolves this promise with a
|
|
14067
|
+
* container, so a window that goes away first would leave the
|
|
14068
|
+
* caller awaiting a promise that never settles - and
|
|
14069
|
+
* `addPopoutGroup` holds its layout transaction open until it does.
|
|
14070
|
+
* Settle with `null` on close, the same signal a blocked popup
|
|
14071
|
+
* gives and one the caller already handles. `resolve` after the
|
|
14072
|
+
* fact is a no-op, so a `load` that arrived first still wins.
|
|
14073
|
+
*/
|
|
14074
|
+
disposable.addDisposables(_this.onWillClose(() => resolve(null)));
|
|
13944
14075
|
externalWindow.addEventListener("load", () => {
|
|
13945
14076
|
/**
|
|
13946
14077
|
* @see https://developer.mozilla.org/en-US/docs/Web/API/Window/load_event
|
|
@@ -15358,6 +15489,7 @@ var DockviewComponent = class extends BaseGrid {
|
|
|
15358
15489
|
this._onWillDrop = new Emitter();
|
|
15359
15490
|
this.onWillDrop = this._onWillDrop.event;
|
|
15360
15491
|
this._mutationDepth = 0;
|
|
15492
|
+
this._pendingLocationChanges = /* @__PURE__ */ new Map();
|
|
15361
15493
|
this._origin = "user";
|
|
15362
15494
|
this._originDepth = 0;
|
|
15363
15495
|
this._onWillMutateLayout = new Emitter();
|
|
@@ -15455,7 +15587,7 @@ var DockviewComponent = class extends BaseGrid {
|
|
|
15455
15587
|
toggleClass(this.element, "dv-debug", !!options.debug);
|
|
15456
15588
|
this.updateTheme();
|
|
15457
15589
|
if (options.debug) this.addDisposables(new StrictEventsSequencing(this));
|
|
15458
|
-
this.addDisposables(this.rootDropTargetContainer, this.floatingDropTargetContainer, addDisposableListener(this._shellManager.element, "dragend", () => {
|
|
15590
|
+
this.addDisposables(Disposable.from(() => this._pendingLocationChanges.clear()), this.rootDropTargetContainer, this.floatingDropTargetContainer, addDisposableListener(this._shellManager.element, "dragend", () => {
|
|
15459
15591
|
var _this$rootDropTargetC2, _this$floatingDropTar;
|
|
15460
15592
|
(_this$rootDropTargetC2 = this.rootDropTargetContainer.model) === null || _this$rootDropTargetC2 === void 0 || _this$rootDropTargetC2.clear();
|
|
15461
15593
|
(_this$floatingDropTar = this.floatingDropTargetContainer.model) === null || _this$floatingDropTar === void 0 || _this$floatingDropTar.clear();
|
|
@@ -15529,7 +15661,7 @@ var DockviewComponent = class extends BaseGrid {
|
|
|
15529
15661
|
return (_this$_popoutWindowSe3 = (_this$_popoutWindowSe4 = this._popoutWindowService) === null || _this$_popoutWindowSe4 === void 0 || (_this$_popoutWindowSe4 = _this$_popoutWindowSe4.findByGroup(group)) === null || _this$_popoutWindowSe4 === void 0 ? void 0 : _this$_popoutWindowSe4.popupService) !== null && _this$_popoutWindowSe3 !== void 0 ? _this$_popoutWindowSe3 : this.popupService;
|
|
15530
15662
|
}
|
|
15531
15663
|
addPopoutGroup(itemToPopout, options) {
|
|
15532
|
-
return this.
|
|
15664
|
+
return this.mutationAsync("popout", () => this._doAddPopoutGroup(itemToPopout, options));
|
|
15533
15665
|
}
|
|
15534
15666
|
/** Enumerate the popout groups currently open in their own windows. */
|
|
15535
15667
|
getPopouts() {
|
|
@@ -15626,15 +15758,32 @@ var DockviewComponent = class extends BaseGrid {
|
|
|
15626
15758
|
}
|
|
15627
15759
|
};
|
|
15628
15760
|
let floatingBox;
|
|
15629
|
-
|
|
15630
|
-
|
|
15631
|
-
|
|
15632
|
-
|
|
15633
|
-
|
|
15761
|
+
/**
|
|
15762
|
+
* Popping out rehomes panels into `group`, so like the floating
|
|
15763
|
+
* case it owes the caller an `onDidMovePanel` per panel. The
|
|
15764
|
+
* events are deferred until the window is wired up so listeners
|
|
15765
|
+
* observe the panels' final `popout` location.
|
|
15766
|
+
*/
|
|
15767
|
+
let movedPanels = [];
|
|
15768
|
+
if (!(options === null || options === void 0 ? void 0 : options.overridePopoutGroup) && !(options === null || options === void 0 ? void 0 : options.overridePopoutGridview) && isGroupAddedToDom) if (itemToPopout instanceof DockviewPanel) {
|
|
15769
|
+
const sourceGroup = itemToPopout.group;
|
|
15770
|
+
this.movingLock(() => {
|
|
15771
|
+
const panel = referenceGroup.model.removePanel(itemToPopout);
|
|
15772
|
+
group.model.openPanel(panel);
|
|
15773
|
+
});
|
|
15774
|
+
movedPanels = [{
|
|
15775
|
+
panel: itemToPopout,
|
|
15776
|
+
from: sourceGroup
|
|
15777
|
+
}];
|
|
15778
|
+
} else {
|
|
15634
15779
|
this.movingLock(() => moveGroupWithoutDestroying({
|
|
15635
15780
|
from: referenceGroup,
|
|
15636
15781
|
to: group
|
|
15637
15782
|
}));
|
|
15783
|
+
movedPanels = group.panels.map((panel) => ({
|
|
15784
|
+
panel,
|
|
15785
|
+
from: referenceGroup
|
|
15786
|
+
}));
|
|
15638
15787
|
switch (referenceLocation) {
|
|
15639
15788
|
case "grid":
|
|
15640
15789
|
referenceGroup.api.setVisible(false);
|
|
@@ -15743,6 +15892,7 @@ var DockviewComponent = class extends BaseGrid {
|
|
|
15743
15892
|
group: value.popoutGroup,
|
|
15744
15893
|
window: value.getWindow()
|
|
15745
15894
|
});
|
|
15895
|
+
for (const { panel, from } of movedPanels) this.fireDidMovePanel(panel, from);
|
|
15746
15896
|
return true;
|
|
15747
15897
|
}).catch((err) => {
|
|
15748
15898
|
console.error("dockview: failed to create popout.", err);
|
|
@@ -15820,6 +15970,16 @@ var DockviewComponent = class extends BaseGrid {
|
|
|
15820
15970
|
const members = this.groups.filter((candidate) => popoutGridview.element.contains(candidate.element));
|
|
15821
15971
|
const anchorPresent = members.includes(group);
|
|
15822
15972
|
const anchorIsSoleMember = anchorPresent && members.length === 1;
|
|
15973
|
+
/**
|
|
15974
|
+
* Popping a group out fires `onDidMovePanel` per panel, so closing the
|
|
15975
|
+
* window owes the caller the same: every panel in it is rehomed, into
|
|
15976
|
+
* the reference group the popout left behind or into a fresh grid slot.
|
|
15977
|
+
* `movingLock` suppresses onDidAddPanel / onDidRemovePanel on these
|
|
15978
|
+
* paths, so `onDidMovePanel` is the only event that can carry it. The
|
|
15979
|
+
* events are deferred to the end so listeners observe the panels at
|
|
15980
|
+
* their final group and location.
|
|
15981
|
+
*/
|
|
15982
|
+
const movedPanels = [];
|
|
15823
15983
|
if (genuineClose) for (const member of members) {
|
|
15824
15984
|
if (member === group) continue;
|
|
15825
15985
|
this.movingLock(() => {
|
|
@@ -15830,12 +15990,21 @@ var DockviewComponent = class extends BaseGrid {
|
|
|
15830
15990
|
});
|
|
15831
15991
|
this.redockGroupToMainGrid(member);
|
|
15832
15992
|
});
|
|
15993
|
+
for (const panel of member.panels) movedPanels.push({
|
|
15994
|
+
panel,
|
|
15995
|
+
from: member
|
|
15996
|
+
});
|
|
15833
15997
|
}
|
|
15834
15998
|
if (anchorPresent && isGroupAddedToDom && this.getPanel(referenceGroup.id)) {
|
|
15999
|
+
const rehomed = [...group.panels];
|
|
15835
16000
|
this.movingLock(() => moveGroupWithoutDestroying({
|
|
15836
16001
|
from: group,
|
|
15837
16002
|
to: referenceGroup
|
|
15838
16003
|
}));
|
|
16004
|
+
for (const panel of rehomed) movedPanels.push({
|
|
16005
|
+
panel,
|
|
16006
|
+
from: group
|
|
16007
|
+
});
|
|
15839
16008
|
if (!referenceGroup.api.isVisible) referenceGroup.api.setVisible(true);
|
|
15840
16009
|
if (this.getPanel(group.id)) this.doRemoveGroup(group, { skipPopoutAssociated: true });
|
|
15841
16010
|
} else if (anchorPresent && this.getPanel(group.id)) {
|
|
@@ -15866,10 +16035,15 @@ var DockviewComponent = class extends BaseGrid {
|
|
|
15866
16035
|
this.movingLock(() => {
|
|
15867
16036
|
this.doAddGroup(group, [0]);
|
|
15868
16037
|
});
|
|
16038
|
+
for (const panel of group.panels) movedPanels.push({
|
|
16039
|
+
panel,
|
|
16040
|
+
from: group
|
|
16041
|
+
});
|
|
15869
16042
|
}
|
|
15870
16043
|
this.doSetGroupAndPanelActive(group);
|
|
15871
16044
|
}
|
|
15872
16045
|
disposePopoutGridview();
|
|
16046
|
+
for (const { panel, from } of movedPanels) this.fireDidMovePanel(panel, from);
|
|
15873
16047
|
}
|
|
15874
16048
|
addFloatingGroup(item, options) {
|
|
15875
16049
|
this.mutation("float", () => this._doAddFloatingGroup(item, options));
|
|
@@ -15878,7 +16052,15 @@ var DockviewComponent = class extends BaseGrid {
|
|
|
15878
16052
|
if (!assertModule(this._floatingGroupService, "FloatingGroup", "api.addFloatingGroup")) return;
|
|
15879
16053
|
if (item instanceof DockviewGroupPanel && item.model.location.type === "edge") return;
|
|
15880
16054
|
let group;
|
|
16055
|
+
/**
|
|
16056
|
+
* Floating relocates panels exactly like a drop onto the grid does, so
|
|
16057
|
+
* it owes the caller an `onDidMovePanel` per panel. The events are
|
|
16058
|
+
* deferred until the window is mounted below: only then do the panels
|
|
16059
|
+
* report their final `floating` location.
|
|
16060
|
+
*/
|
|
16061
|
+
let movedPanels = [];
|
|
15881
16062
|
if (item instanceof DockviewPanel) {
|
|
16063
|
+
const sourceGroup = item.group;
|
|
15882
16064
|
group = this.createGroup();
|
|
15883
16065
|
this._onDidAddGroup.fire(group);
|
|
15884
16066
|
this.movingLock(() => this.removePanel(item, {
|
|
@@ -15887,6 +16069,10 @@ var DockviewComponent = class extends BaseGrid {
|
|
|
15887
16069
|
skipSetActiveGroup: true
|
|
15888
16070
|
}));
|
|
15889
16071
|
this.movingLock(() => group.model.openPanel(item, { skipSetGroupActive: true }));
|
|
16072
|
+
movedPanels = [{
|
|
16073
|
+
panel: item,
|
|
16074
|
+
from: sourceGroup
|
|
16075
|
+
}];
|
|
15890
16076
|
} else {
|
|
15891
16077
|
var _this$_popoutWindowSe8;
|
|
15892
16078
|
group = item;
|
|
@@ -15903,11 +16089,21 @@ var DockviewComponent = class extends BaseGrid {
|
|
|
15903
16089
|
});
|
|
15904
16090
|
this.doRemoveGroup(popoutReferenceGroup, { skipDispose: true });
|
|
15905
16091
|
group = popoutReferenceGroup;
|
|
15906
|
-
|
|
15907
|
-
|
|
15908
|
-
|
|
15909
|
-
|
|
15910
|
-
}
|
|
16092
|
+
movedPanels = group.panels.map((panel) => ({
|
|
16093
|
+
panel,
|
|
16094
|
+
from: item
|
|
16095
|
+
}));
|
|
16096
|
+
} else {
|
|
16097
|
+
this.doRemoveGroup(item, {
|
|
16098
|
+
skipDispose: true,
|
|
16099
|
+
skipPopoutReturn: true,
|
|
16100
|
+
skipPopoutAssociated: false
|
|
16101
|
+
});
|
|
16102
|
+
movedPanels = group.panels.map((panel) => ({
|
|
16103
|
+
panel,
|
|
16104
|
+
from: group
|
|
16105
|
+
}));
|
|
16106
|
+
}
|
|
15911
16107
|
}
|
|
15912
16108
|
function getAnchoredBox() {
|
|
15913
16109
|
if (options === null || options === void 0 ? void 0 : options.position) {
|
|
@@ -15940,6 +16136,7 @@ var DockviewComponent = class extends BaseGrid {
|
|
|
15940
16136
|
skipActiveGroup: options === null || options === void 0 ? void 0 : options.skipActiveGroup,
|
|
15941
16137
|
disableSmartGuides: options === null || options === void 0 ? void 0 : options.disableSmartGuides
|
|
15942
16138
|
});
|
|
16139
|
+
for (const { panel, from } of movedPanels) this.fireDidMovePanel(panel, from);
|
|
15943
16140
|
}
|
|
15944
16141
|
/**
|
|
15945
16142
|
* Build an empty gridview configured to match the main grid's styling, for
|
|
@@ -16371,35 +16568,119 @@ var DockviewComponent = class extends BaseGrid {
|
|
|
16371
16568
|
if (typeof data !== "object" || data === null) throw new Error("dockview: serialized layout must be a non-null object");
|
|
16372
16569
|
if (!data.grid || ((_data$grid$root = data.grid.root) === null || _data$grid$root === void 0 ? void 0 : _data$grid$root.type) !== "branch" || !Array.isArray(data.grid.root.data)) throw new Error("dockview: root must be of type branch");
|
|
16373
16570
|
const existingPanels = /* @__PURE__ */ new Map();
|
|
16374
|
-
|
|
16571
|
+
const temporaryGroups = /* @__PURE__ */ new Map();
|
|
16572
|
+
const stagedPanels = [];
|
|
16573
|
+
const temporaryGroupDisposables = [];
|
|
16574
|
+
/**
|
|
16575
|
+
* The staging groups are detached from `_groups` and never enter the
|
|
16576
|
+
* grid, so nothing else will ever tear them down.
|
|
16577
|
+
*
|
|
16578
|
+
* `dispose()` reaches consumer `IContentRenderer.dispose()`, so one
|
|
16579
|
+
* throwing renderer must not abort the rest of the cleanup — that would
|
|
16580
|
+
* re-introduce the very leak this reclaims — nor replace the
|
|
16581
|
+
* deserialization error the caller is being given. Draining the list
|
|
16582
|
+
* also makes this safe to call more than once.
|
|
16583
|
+
*/
|
|
16584
|
+
const disposeTemporaryGroups = () => {
|
|
16585
|
+
for (const disposable of temporaryGroupDisposables) try {
|
|
16586
|
+
disposable.dispose();
|
|
16587
|
+
} catch (err) {
|
|
16588
|
+
console.error("dockview: failed to dispose a temporary group created for reuseExistingPanels", err);
|
|
16589
|
+
}
|
|
16590
|
+
temporaryGroupDisposables.length = 0;
|
|
16591
|
+
};
|
|
16375
16592
|
if (options === null || options === void 0 ? void 0 : options.reuseExistingPanels) {
|
|
16376
16593
|
/**
|
|
16377
|
-
*
|
|
16378
|
-
*
|
|
16379
|
-
*
|
|
16380
|
-
* 2. Remove that temporary group from the group mapping so that it doesn't get cleared when we clear the layout
|
|
16594
|
+
* Visible, always-rendered panels need individual staging groups
|
|
16595
|
+
* to remain active. Other reused panels can share a staging group.
|
|
16596
|
+
* The staging groups are excluded from the layout clear below.
|
|
16381
16597
|
*/
|
|
16382
|
-
tempGroup = this.createGroup();
|
|
16383
|
-
this._groups.delete(tempGroup.api.id);
|
|
16384
16598
|
const newPanels = Object.keys(data.panels);
|
|
16385
|
-
|
|
16386
|
-
|
|
16387
|
-
|
|
16388
|
-
|
|
16389
|
-
|
|
16390
|
-
|
|
16391
|
-
|
|
16392
|
-
|
|
16393
|
-
|
|
16394
|
-
|
|
16395
|
-
|
|
16396
|
-
|
|
16397
|
-
|
|
16599
|
+
let sharedTemporaryGroup;
|
|
16600
|
+
const createTemporaryGroup = () => {
|
|
16601
|
+
const temporaryGroup = this.createGroup();
|
|
16602
|
+
/**
|
|
16603
|
+
* Removing the group from `_groups` also drops the record's
|
|
16604
|
+
* `CompositeDisposable`, so capture it first and tear both it
|
|
16605
|
+
* and the group down in the `finally` below. Left undisposed a
|
|
16606
|
+
* staging group leaks its `ResizeObserver`, its
|
|
16607
|
+
* `onDidOptionsChange` subscription (retained by this
|
|
16608
|
+
* component's emitter) and the watermark its model mounts when
|
|
16609
|
+
* the group empties — once per reused panel, per `fromJSON`.
|
|
16610
|
+
*/
|
|
16611
|
+
const record = this._groups.get(temporaryGroup.api.id);
|
|
16612
|
+
this._groups.delete(temporaryGroup.api.id);
|
|
16613
|
+
temporaryGroupDisposables.push(Disposable.from(() => {
|
|
16614
|
+
/**
|
|
16615
|
+
* Reclaim the group's own resources, never its panels.
|
|
16616
|
+
* Staging is driven by the ids in `data.panels` while
|
|
16617
|
+
* reclaiming is driven by the group `views` that
|
|
16618
|
+
* reference them, so a panel whose state is present but
|
|
16619
|
+
* unreferenced is still staged here — and `dispose()`
|
|
16620
|
+
* on a non-empty group reaches the consumer's
|
|
16621
|
+
* `IContentRenderer.dispose()`. Emptying the group
|
|
16622
|
+
* first leaves those panels exactly as they were before
|
|
16623
|
+
* this teardown existed, which also keeps this safe
|
|
16624
|
+
* against any future path that rebuilds a panel under
|
|
16625
|
+
* an id that is live in the new layout.
|
|
16626
|
+
*/
|
|
16627
|
+
this.movingLock(() => {
|
|
16628
|
+
for (const panel of temporaryGroup.panels.slice()) temporaryGroup.model.removePanel(panel);
|
|
16629
|
+
});
|
|
16630
|
+
record === null || record === void 0 || record.disposable.dispose();
|
|
16631
|
+
temporaryGroup.dispose();
|
|
16632
|
+
}));
|
|
16633
|
+
return temporaryGroup;
|
|
16634
|
+
};
|
|
16635
|
+
/**
|
|
16636
|
+
* Staging and the clear below run before the deserialization
|
|
16637
|
+
* `try`, so a throw here (a consumer `onDidRemovePanel` handler, a
|
|
16638
|
+
* renderer teardown during `clear`) would escape without reclaiming
|
|
16639
|
+
* the staging groups already created.
|
|
16640
|
+
*
|
|
16641
|
+
* The creation loop is inside the guard too, not just the moves and
|
|
16642
|
+
* the clear: `createGroup()` reaches consumer code of its own —
|
|
16643
|
+
* `initialize()` mounts the watermark through
|
|
16644
|
+
* `createWatermarkComponent()` — so a throw on the n-th panel would
|
|
16645
|
+
* otherwise strand the n-1 staging groups already built.
|
|
16646
|
+
*/
|
|
16647
|
+
try {
|
|
16648
|
+
for (const panel of this.panels) if (newPanels.includes(panel.api.id)) {
|
|
16649
|
+
existingPanels.set(panel.api.id, panel);
|
|
16650
|
+
let temporaryGroup;
|
|
16651
|
+
if (panel.api.renderer === "always" && panel.api.isVisible) temporaryGroup = createTemporaryGroup();
|
|
16652
|
+
else {
|
|
16653
|
+
var _sharedTemporaryGroup;
|
|
16654
|
+
(_sharedTemporaryGroup = sharedTemporaryGroup) !== null && _sharedTemporaryGroup !== void 0 || (sharedTemporaryGroup = createTemporaryGroup());
|
|
16655
|
+
temporaryGroup = sharedTemporaryGroup;
|
|
16656
|
+
}
|
|
16657
|
+
temporaryGroups.set(panel.api.id, temporaryGroup);
|
|
16658
|
+
stagedPanels.push({
|
|
16659
|
+
panel,
|
|
16660
|
+
temporaryGroup
|
|
16661
|
+
});
|
|
16662
|
+
}
|
|
16663
|
+
this.movingLock(() => {
|
|
16664
|
+
stagedPanels.forEach(({ panel, temporaryGroup }) => {
|
|
16665
|
+
this.moveGroupOrPanel({
|
|
16666
|
+
from: {
|
|
16667
|
+
groupId: panel.api.group.api.id,
|
|
16668
|
+
panelId: panel.api.id
|
|
16669
|
+
},
|
|
16670
|
+
to: {
|
|
16671
|
+
group: temporaryGroup,
|
|
16672
|
+
position: "center"
|
|
16673
|
+
},
|
|
16674
|
+
keepEmptyGroups: true
|
|
16675
|
+
});
|
|
16398
16676
|
});
|
|
16399
16677
|
});
|
|
16400
|
-
|
|
16401
|
-
|
|
16402
|
-
|
|
16678
|
+
this.clear();
|
|
16679
|
+
} catch (err) {
|
|
16680
|
+
disposeTemporaryGroups();
|
|
16681
|
+
throw err;
|
|
16682
|
+
}
|
|
16683
|
+
} else this.clear();
|
|
16403
16684
|
const { grid, panels, activeGroup } = data;
|
|
16404
16685
|
try {
|
|
16405
16686
|
var _data$floatingGroups, _data$popoutGroups, _this$_popoutWindowSe12, _this$_floatingGroupS5, _this$_watermarkServi2;
|
|
@@ -16431,9 +16712,10 @@ var DockviewComponent = class extends BaseGrid {
|
|
|
16431
16712
|
* due to a corruption of input data.
|
|
16432
16713
|
*/
|
|
16433
16714
|
const existingPanel = existingPanels.get(child);
|
|
16434
|
-
|
|
16715
|
+
const temporaryGroup = temporaryGroups.get(child);
|
|
16716
|
+
if (temporaryGroup && existingPanel) {
|
|
16435
16717
|
this.movingLock(() => {
|
|
16436
|
-
|
|
16718
|
+
temporaryGroup.model.removePanel(existingPanel);
|
|
16437
16719
|
});
|
|
16438
16720
|
createdPanels.push(existingPanel);
|
|
16439
16721
|
existingPanel.updateFromStateModel(panels[child]);
|
|
@@ -16463,7 +16745,7 @@ var DockviewComponent = class extends BaseGrid {
|
|
|
16463
16745
|
return createGroupFromSerializedState(node.data);
|
|
16464
16746
|
} });
|
|
16465
16747
|
this._layoutFromShell(width, height);
|
|
16466
|
-
if (data.edgeGroups) this.deserializeEdgeGroups(data.edgeGroups, panels);
|
|
16748
|
+
if (data.edgeGroups) this.deserializeEdgeGroups(data.edgeGroups, panels, existingPanels, temporaryGroups);
|
|
16467
16749
|
this.deserializeFloatingWindows((_data$floatingGroups = data.floatingGroups) !== null && _data$floatingGroups !== void 0 ? _data$floatingGroups : [], createGroupFromSerializedState);
|
|
16468
16750
|
const popoutPromises = this.deserializePopoutWindows((_data$popoutGroups = data.popoutGroups) !== null && _data$popoutGroups !== void 0 ? _data$popoutGroups : [], createGroupFromSerializedState);
|
|
16469
16751
|
(_this$_popoutWindowSe12 = this._popoutWindowService) === null || _this$_popoutWindowSe12 === void 0 || _this$_popoutWindowSe12.finishRestoration(popoutPromises);
|
|
@@ -16500,6 +16782,8 @@ var DockviewComponent = class extends BaseGrid {
|
|
|
16500
16782
|
* expect trying to load a corrupted layout to result in an error and not silently fail...
|
|
16501
16783
|
*/
|
|
16502
16784
|
throw err;
|
|
16785
|
+
} finally {
|
|
16786
|
+
disposeTemporaryGroups();
|
|
16503
16787
|
}
|
|
16504
16788
|
this.debouncedUpdateAllPositions();
|
|
16505
16789
|
this._onDidLayoutFromJSON.fire();
|
|
@@ -16522,7 +16806,7 @@ var DockviewComponent = class extends BaseGrid {
|
|
|
16522
16806
|
members
|
|
16523
16807
|
};
|
|
16524
16808
|
}
|
|
16525
|
-
deserializeEdgeGroups(edgeGroups, panels) {
|
|
16809
|
+
deserializeEdgeGroups(edgeGroups, panels, existingPanels, temporaryGroups) {
|
|
16526
16810
|
const edgeService = assertModule(this._edgeGroupService, "EdgeGroup", "fromJSON edge restoration");
|
|
16527
16811
|
if (!edgeService) return;
|
|
16528
16812
|
for (const _position of [
|
|
@@ -16552,13 +16836,40 @@ var DockviewComponent = class extends BaseGrid {
|
|
|
16552
16836
|
if (groupState) {
|
|
16553
16837
|
const { views, activeView } = groupState;
|
|
16554
16838
|
const createdPanels = [];
|
|
16555
|
-
for (const panelId of views)
|
|
16556
|
-
|
|
16557
|
-
|
|
16839
|
+
for (const panelId of views) {
|
|
16840
|
+
if (!panels[panelId]) continue;
|
|
16841
|
+
/**
|
|
16842
|
+
* Reclaim a staged panel rather than rebuilding it, the
|
|
16843
|
+
* same way the grid path does. Deserializing here instead
|
|
16844
|
+
* would honour `reuseExistingPanels` everywhere except edge
|
|
16845
|
+
* groups: the live panel keeps sitting in its staging group
|
|
16846
|
+
* while a second panel is built under the same id, so the
|
|
16847
|
+
* consumer's renderer for the original is orphaned — never
|
|
16848
|
+
* disposed, and its element left inside the id-keyed
|
|
16849
|
+
* overlay entry the replacement now shares.
|
|
16850
|
+
*/
|
|
16851
|
+
const existingPanel = existingPanels.get(panelId);
|
|
16852
|
+
const temporaryGroup = temporaryGroups.get(panelId);
|
|
16853
|
+
if (temporaryGroup && existingPanel) {
|
|
16854
|
+
this.movingLock(() => {
|
|
16855
|
+
temporaryGroup.model.removePanel(existingPanel);
|
|
16856
|
+
});
|
|
16857
|
+
createdPanels.push(existingPanel);
|
|
16858
|
+
existingPanel.updateFromStateModel(panels[panelId]);
|
|
16859
|
+
} else {
|
|
16860
|
+
const panel = this._deserializer.fromJSON(panels[panelId], edgeGroup);
|
|
16861
|
+
createdPanels.push(panel);
|
|
16862
|
+
}
|
|
16558
16863
|
}
|
|
16559
16864
|
for (const panel of createdPanels) {
|
|
16560
16865
|
const isActive = activeView === panel.id;
|
|
16561
|
-
|
|
16866
|
+
if (existingPanels.has(panel.api.id)) this.movingLock(() => {
|
|
16867
|
+
edgeGroup.model.openPanel(panel, {
|
|
16868
|
+
skipSetActive: !isActive,
|
|
16869
|
+
skipSetGroupActive: true
|
|
16870
|
+
});
|
|
16871
|
+
});
|
|
16872
|
+
else edgeGroup.model.openPanel(panel, {
|
|
16562
16873
|
skipSetActive: !isActive,
|
|
16563
16874
|
skipSetGroupActive: true
|
|
16564
16875
|
});
|
|
@@ -16982,22 +17293,100 @@ var DockviewComponent = class extends BaseGrid {
|
|
|
16982
17293
|
* outermost mutation.
|
|
16983
17294
|
*/
|
|
16984
17295
|
mutation(kind, func) {
|
|
16985
|
-
const
|
|
17296
|
+
const close = this.openMutation(kind);
|
|
17297
|
+
try {
|
|
17298
|
+
return func();
|
|
17299
|
+
} finally {
|
|
17300
|
+
close();
|
|
17301
|
+
}
|
|
17302
|
+
}
|
|
17303
|
+
/**
|
|
17304
|
+
* `mutation()` for an operation whose work continues after the synchronous
|
|
17305
|
+
* call returns. The transaction stays open until the returned promise
|
|
17306
|
+
* settles, so everything the operation does - the group it adds, the panels
|
|
17307
|
+
* it relocates - lands inside the bracket, matching the synchronous
|
|
17308
|
+
* move / float paths.
|
|
17309
|
+
*/
|
|
17310
|
+
mutationAsync(kind, func) {
|
|
17311
|
+
var _this = this;
|
|
17312
|
+
return _asyncToGenerator(function* () {
|
|
17313
|
+
const close = _this.openMutation(kind);
|
|
17314
|
+
try {
|
|
17315
|
+
return yield func();
|
|
17316
|
+
} finally {
|
|
17317
|
+
close();
|
|
17318
|
+
}
|
|
17319
|
+
})();
|
|
17320
|
+
}
|
|
17321
|
+
/**
|
|
17322
|
+
* Open a transaction and return the function that closes it. Shared by the
|
|
17323
|
+
* synchronous and asynchronous brackets; the returned function must be
|
|
17324
|
+
* called exactly once.
|
|
17325
|
+
*
|
|
17326
|
+
* Both ends key off the depth counter reaching zero rather than off which
|
|
17327
|
+
* bracket opened first. For synchronous nesting the two are the same thing
|
|
17328
|
+
* - brackets close in the order they opened - but asynchronous transactions
|
|
17329
|
+
* can *overlap* rather than nest (two `addPopoutGroup` calls in flight at
|
|
17330
|
+
* once, or a restore staggering several), and there the first to open is
|
|
17331
|
+
* not the last to close. Reporting on the opener would fire `didMutate`
|
|
17332
|
+
* while the other transaction was still doing structural work, which is the
|
|
17333
|
+
* very thing the async bracket exists to prevent. Overlapping transactions
|
|
17334
|
+
* therefore report as one, tagged with the kind of the last to finish.
|
|
17335
|
+
*/
|
|
17336
|
+
openMutation(kind) {
|
|
16986
17337
|
const origin = this._origin;
|
|
16987
|
-
if (
|
|
17338
|
+
if (this._mutationDepth === 0) this._onWillMutateLayout.fire({
|
|
16988
17339
|
kind,
|
|
16989
17340
|
origin
|
|
16990
17341
|
});
|
|
16991
17342
|
this._mutationDepth++;
|
|
16992
|
-
|
|
16993
|
-
return func();
|
|
16994
|
-
} finally {
|
|
17343
|
+
return () => {
|
|
16995
17344
|
this._mutationDepth--;
|
|
16996
|
-
if (
|
|
16997
|
-
|
|
16998
|
-
|
|
16999
|
-
|
|
17345
|
+
if (this._mutationDepth === 0) {
|
|
17346
|
+
this.flushLocationChanges();
|
|
17347
|
+
this._onDidMutateLayout.fire({
|
|
17348
|
+
kind,
|
|
17349
|
+
origin
|
|
17350
|
+
});
|
|
17351
|
+
}
|
|
17352
|
+
};
|
|
17353
|
+
}
|
|
17354
|
+
/**
|
|
17355
|
+
* Coalesce a panel's `onDidLocationChange` to the end of the enclosing
|
|
17356
|
+
* transaction, or fire it immediately when no transaction is in flight.
|
|
17357
|
+
*
|
|
17358
|
+
* Relocating a panel touches its location twice: once as it is reparented
|
|
17359
|
+
* into the destination group - which, when that group has just been created
|
|
17360
|
+
* for a floating or popout window, has not been told where it lives yet -
|
|
17361
|
+
* and once as the group is tagged with its final location. Reporting each
|
|
17362
|
+
* signal as it happens therefore leaks an intermediate `grid` location the
|
|
17363
|
+
* panel was never in, at a moment when it belongs to neither group's panel
|
|
17364
|
+
* list and so is missing from `api.panels`.
|
|
17365
|
+
*
|
|
17366
|
+
* Deferring collapses those signals into a single event carrying the
|
|
17367
|
+
* settled location. Note the signals are deliberately *not* compared
|
|
17368
|
+
* against the panel's previous location: a panel can move between two
|
|
17369
|
+
* floating windows without its location type changing, and this event is
|
|
17370
|
+
* the only signal `OverlayRenderContainer` has to re-resolve the panel's
|
|
17371
|
+
* z-index against its new host window.
|
|
17372
|
+
*/
|
|
17373
|
+
deferLocationChange(key, fire) {
|
|
17374
|
+
if (this._mutationDepth === 0) {
|
|
17375
|
+
fire();
|
|
17376
|
+
return;
|
|
17000
17377
|
}
|
|
17378
|
+
this._pendingLocationChanges.set(key, fire);
|
|
17379
|
+
}
|
|
17380
|
+
/**
|
|
17381
|
+
* Report every panel whose location moved during the transaction that has
|
|
17382
|
+
* just closed. Each callback reads the panel's location at this point, so
|
|
17383
|
+
* what it reports is where the panel ended up.
|
|
17384
|
+
*/
|
|
17385
|
+
flushLocationChanges() {
|
|
17386
|
+
if (this._pendingLocationChanges.size === 0) return;
|
|
17387
|
+
const pending = Array.from(this._pendingLocationChanges.values());
|
|
17388
|
+
this._pendingLocationChanges.clear();
|
|
17389
|
+
for (const fire of pending) fire();
|
|
17001
17390
|
}
|
|
17002
17391
|
/**
|
|
17003
17392
|
* The origin of the operation currently in progress (`'user'` by default).
|
|
@@ -17038,6 +17427,18 @@ var DockviewComponent = class extends BaseGrid {
|
|
|
17038
17427
|
origin: this._origin
|
|
17039
17428
|
});
|
|
17040
17429
|
}
|
|
17430
|
+
/**
|
|
17431
|
+
* Announce that `panel` has finished relocating. Must be called once the
|
|
17432
|
+
* move has settled: `to` is read from the panel's current group, so an
|
|
17433
|
+
* early call would report the source group as the destination.
|
|
17434
|
+
*/
|
|
17435
|
+
fireDidMovePanel(panel, from) {
|
|
17436
|
+
this._onDidMovePanel.fire({
|
|
17437
|
+
panel,
|
|
17438
|
+
from,
|
|
17439
|
+
to: panel.group
|
|
17440
|
+
});
|
|
17441
|
+
}
|
|
17041
17442
|
moveGroupOrPanel(options) {
|
|
17042
17443
|
this.mutation("move", () => this._doMoveGroupOrPanel(options));
|
|
17043
17444
|
}
|
|
@@ -17098,10 +17499,7 @@ var DockviewComponent = class extends BaseGrid {
|
|
|
17098
17499
|
});
|
|
17099
17500
|
});
|
|
17100
17501
|
if (!options.skipSetActive) this.doSetGroupAndPanelActive(destinationGroup);
|
|
17101
|
-
this.
|
|
17102
|
-
panel: removedPanel,
|
|
17103
|
-
from: sourceGroup
|
|
17104
|
-
});
|
|
17502
|
+
this.fireDidMovePanel(removedPanel, sourceGroup);
|
|
17105
17503
|
} else {
|
|
17106
17504
|
/**
|
|
17107
17505
|
* Dropping a panel to the extremities of a group which will place that panel
|
|
@@ -17120,10 +17518,7 @@ var DockviewComponent = class extends BaseGrid {
|
|
|
17120
17518
|
const [sourceParentLocation, from] = tail(getGridLocation(sourceGroup.element));
|
|
17121
17519
|
if (sequenceEquals(sourceParentLocation, targetParentLocation)) {
|
|
17122
17520
|
this.gridview.moveView(sourceParentLocation, from, to);
|
|
17123
|
-
this.
|
|
17124
|
-
panel: this.getGroupPanel(sourceItemId),
|
|
17125
|
-
from: sourceGroup
|
|
17126
|
-
});
|
|
17521
|
+
this.fireDidMovePanel(this.getGroupPanel(sourceItemId), sourceGroup);
|
|
17127
17522
|
return;
|
|
17128
17523
|
}
|
|
17129
17524
|
}
|
|
@@ -17154,10 +17549,7 @@ var DockviewComponent = class extends BaseGrid {
|
|
|
17154
17549
|
const newGroup = this.createGroupAtLocation(updatedTargetLocation, void 0, void 0, destinationGridview);
|
|
17155
17550
|
this.movingLock(() => newGroup.model.openPanel(removedPanel, { skipSetActive: true }));
|
|
17156
17551
|
this.doSetGroupAndPanelActive(newGroup);
|
|
17157
|
-
this.
|
|
17158
|
-
panel: this.getGroupPanel(sourceItemId),
|
|
17159
|
-
from: sourceGroup
|
|
17160
|
-
});
|
|
17552
|
+
this.fireDidMovePanel(this.getGroupPanel(sourceItemId), sourceGroup);
|
|
17161
17553
|
return;
|
|
17162
17554
|
}
|
|
17163
17555
|
if (sourceGroup.api.location.type === "edge") {
|
|
@@ -17174,10 +17566,7 @@ var DockviewComponent = class extends BaseGrid {
|
|
|
17174
17566
|
const newGroup = this.createGroupAtLocation(targetLocation, void 0, void 0, destinationGridview);
|
|
17175
17567
|
this.movingLock(() => newGroup.model.openPanel(removedPanel, { skipSetGroupActive: true }));
|
|
17176
17568
|
this.doSetGroupAndPanelActive(newGroup);
|
|
17177
|
-
this.
|
|
17178
|
-
panel: removedPanel,
|
|
17179
|
-
from: sourceGroup
|
|
17180
|
-
});
|
|
17569
|
+
this.fireDidMovePanel(removedPanel, sourceGroup);
|
|
17181
17570
|
return;
|
|
17182
17571
|
}
|
|
17183
17572
|
const targetGroup = this.movingLock(() => this.doRemoveGroup(sourceGroup, {
|
|
@@ -17189,10 +17578,7 @@ var DockviewComponent = class extends BaseGrid {
|
|
|
17189
17578
|
this.movingLock(() => this.doAddGroup(targetGroup, location, void 0, destinationGridview));
|
|
17190
17579
|
this.setGroupLocationForRoot(targetGroup, destinationGridview);
|
|
17191
17580
|
this.doSetGroupAndPanelActive(targetGroup);
|
|
17192
|
-
this.
|
|
17193
|
-
panel: this.getGroupPanel(sourceItemId),
|
|
17194
|
-
from: sourceGroup
|
|
17195
|
-
});
|
|
17581
|
+
this.fireDidMovePanel(this.getGroupPanel(sourceItemId), sourceGroup);
|
|
17196
17582
|
} else {
|
|
17197
17583
|
/**
|
|
17198
17584
|
* The group we are removing from has many panels, we need to remove the panels we are moving,
|
|
@@ -17207,10 +17593,7 @@ var DockviewComponent = class extends BaseGrid {
|
|
|
17207
17593
|
const group = this.createGroupAtLocation(dropLocation, void 0, void 0, destinationGridview);
|
|
17208
17594
|
this.movingLock(() => group.model.openPanel(removedPanel, { skipSetGroupActive: true }));
|
|
17209
17595
|
this.doSetGroupAndPanelActive(group);
|
|
17210
|
-
this.
|
|
17211
|
-
panel: removedPanel,
|
|
17212
|
-
from: sourceGroup
|
|
17213
|
-
});
|
|
17596
|
+
this.fireDidMovePanel(removedPanel, sourceGroup);
|
|
17214
17597
|
}
|
|
17215
17598
|
}
|
|
17216
17599
|
}
|
|
@@ -17245,10 +17628,7 @@ var DockviewComponent = class extends BaseGrid {
|
|
|
17245
17628
|
});
|
|
17246
17629
|
for (const panel of removedPanels) targetGroup.model.addPanelToTabGroup(newTabGroup.id, panel.id);
|
|
17247
17630
|
if (!options.skipSetActive) this.doSetGroupAndPanelActive(targetGroup);
|
|
17248
|
-
for (const panel of removedPanels) this.
|
|
17249
|
-
panel,
|
|
17250
|
-
from: sourceGroup
|
|
17251
|
-
});
|
|
17631
|
+
for (const panel of removedPanels) this.fireDidMovePanel(panel, sourceGroup);
|
|
17252
17632
|
};
|
|
17253
17633
|
let targetGroup;
|
|
17254
17634
|
if (!destinationTarget || destinationTarget === "center" || !referenceLocation) targetGroup = destinationGroup;
|
|
@@ -17269,10 +17649,12 @@ var DockviewComponent = class extends BaseGrid {
|
|
|
17269
17649
|
this.mutation("maximize", () => super.exitMaximizedGroup());
|
|
17270
17650
|
}
|
|
17271
17651
|
_doMoveGroup(options) {
|
|
17652
|
+
var _mergedPanels;
|
|
17272
17653
|
const from = options.from.group;
|
|
17273
17654
|
const to = options.to.group;
|
|
17274
17655
|
const target = options.to.position;
|
|
17275
17656
|
let source = from;
|
|
17657
|
+
let mergedPanels;
|
|
17276
17658
|
if (target === "center") {
|
|
17277
17659
|
const activePanel = from.activePanel;
|
|
17278
17660
|
const tabGroupSnapshots = from.model.getTabGroups().map((tg) => ({
|
|
@@ -17290,6 +17672,7 @@ var DockviewComponent = class extends BaseGrid {
|
|
|
17290
17672
|
skipSetGroupActive: true
|
|
17291
17673
|
});
|
|
17292
17674
|
});
|
|
17675
|
+
mergedPanels = panels;
|
|
17293
17676
|
for (const snapshot of tabGroupSnapshots) {
|
|
17294
17677
|
const newTabGroup = to.model.createTabGroup({
|
|
17295
17678
|
label: snapshot.label,
|
|
@@ -17379,11 +17762,8 @@ var DockviewComponent = class extends BaseGrid {
|
|
|
17379
17762
|
this.setGroupLocationForRoot(source, destGridview);
|
|
17380
17763
|
}
|
|
17381
17764
|
}
|
|
17382
|
-
source.panels.forEach((panel) => {
|
|
17383
|
-
this.
|
|
17384
|
-
panel,
|
|
17385
|
-
from
|
|
17386
|
-
});
|
|
17765
|
+
((_mergedPanels = mergedPanels) !== null && _mergedPanels !== void 0 ? _mergedPanels : source.panels).forEach((panel) => {
|
|
17766
|
+
this.fireDidMovePanel(panel, from);
|
|
17387
17767
|
});
|
|
17388
17768
|
this.debouncedUpdateAllPositions();
|
|
17389
17769
|
if (options.skipSetActive === false) {
|