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