dockview-core 6.2.2 → 6.4.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/README.md +1 -0
- package/dist/cjs/api/dockviewGroupPanelApi.d.ts +10 -1
- package/dist/cjs/api/dockviewGroupPanelApi.js +16 -0
- package/dist/cjs/dnd/backend.d.ts +70 -0
- package/dist/cjs/dnd/backend.js +171 -0
- package/dist/cjs/dnd/dropOverlay.d.ts +20 -0
- package/dist/cjs/dnd/dropOverlay.js +197 -0
- package/dist/cjs/dnd/droptarget.d.ts +20 -6
- package/dist/cjs/dnd/droptarget.js +14 -208
- package/dist/cjs/dnd/pointer/index.d.ts +11 -0
- package/dist/cjs/dnd/pointer/index.js +13 -0
- package/dist/cjs/dnd/pointer/longPress.d.ts +32 -0
- package/dist/cjs/dnd/pointer/longPress.js +151 -0
- package/dist/cjs/dnd/pointer/pointerDragController.d.ts +60 -0
- package/dist/cjs/dnd/pointer/pointerDragController.js +241 -0
- package/dist/cjs/dnd/pointer/pointerDragSource.d.ts +61 -0
- package/dist/cjs/dnd/pointer/pointerDragSource.js +195 -0
- package/dist/cjs/dnd/pointer/pointerDropTarget.d.ts +39 -0
- package/dist/cjs/dnd/pointer/pointerDropTarget.js +198 -0
- package/dist/cjs/dnd/pointer/pointerGhost.d.ts +30 -0
- package/dist/cjs/dnd/pointer/pointerGhost.js +44 -0
- package/dist/cjs/dnd/pointer/types.d.ts +16 -0
- package/dist/cjs/dnd/pointer/types.js +2 -0
- package/dist/cjs/dockview/components/panel/content.d.ts +3 -1
- package/dist/cjs/dockview/components/panel/content.js +33 -16
- package/dist/cjs/dockview/components/popupService.js +34 -0
- package/dist/cjs/dockview/components/tab/tab.d.ts +11 -3
- package/dist/cjs/dockview/components/tab/tab.js +151 -117
- package/dist/cjs/dockview/components/titlebar/tabGroupChip.d.ts +9 -2
- package/dist/cjs/dockview/components/titlebar/tabGroupChip.js +15 -6
- package/dist/cjs/dockview/components/titlebar/tabGroupIndicator.js +2 -2
- package/dist/cjs/dockview/components/titlebar/tabGroups.d.ts +33 -5
- package/dist/cjs/dockview/components/titlebar/tabGroups.js +231 -40
- package/dist/cjs/dockview/components/titlebar/tabs.d.ts +38 -1
- package/dist/cjs/dockview/components/titlebar/tabs.js +381 -253
- package/dist/cjs/dockview/components/titlebar/tabsContainer.d.ts +5 -3
- package/dist/cjs/dockview/components/titlebar/voidContainer.d.ts +6 -2
- package/dist/cjs/dockview/components/titlebar/voidContainer.js +190 -22
- package/dist/cjs/dockview/contextMenu.js +19 -4
- package/dist/cjs/dockview/dndCapabilities.d.ts +19 -0
- package/dist/cjs/dockview/dndCapabilities.js +39 -0
- package/dist/cjs/dockview/dockviewComponent.d.ts +2 -0
- package/dist/cjs/dockview/dockviewComponent.js +241 -158
- package/dist/cjs/dockview/dockviewGroupPanelModel.d.ts +10 -5
- package/dist/cjs/dockview/dockviewGroupPanelModel.js +34 -11
- package/dist/cjs/dockview/dockviewPanel.js +5 -0
- package/dist/cjs/dockview/dockviewPanelModel.d.ts +2 -0
- package/dist/cjs/dockview/dockviewPanelModel.js +8 -0
- package/dist/cjs/dockview/events.d.ts +2 -1
- package/dist/cjs/dockview/events.js +1 -0
- package/dist/cjs/dockview/framework.d.ts +8 -0
- package/dist/cjs/dockview/options.d.ts +31 -5
- package/dist/cjs/dockview/options.js +3 -0
- package/dist/cjs/dom.d.ts +5 -1
- package/dist/cjs/dom.js +21 -5
- package/dist/cjs/index.d.ts +1 -1
- package/dist/cjs/overlay/overlay.d.ts +12 -0
- package/dist/cjs/overlay/overlay.js +84 -16
- package/dist/cjs/paneview/draggablePaneviewPanel.d.ts +3 -1
- package/dist/cjs/paneview/draggablePaneviewPanel.js +27 -26
- package/dist/cjs/paneview/options.d.ts +4 -3
- package/dist/cjs/popoutWindow.d.ts +2 -0
- package/dist/cjs/popoutWindow.js +3 -1
- package/dist/dockview-core.js +2431 -937
- package/dist/dockview-core.min.js +2 -2
- package/dist/dockview-core.min.js.map +1 -1
- package/dist/dockview-core.min.noStyle.js +2 -2
- package/dist/dockview-core.min.noStyle.js.map +1 -1
- package/dist/dockview-core.noStyle.js +2430 -936
- package/dist/esm/api/dockviewGroupPanelApi.d.ts +10 -1
- package/dist/esm/api/dockviewGroupPanelApi.js +12 -0
- package/dist/esm/dnd/backend.d.ts +70 -0
- package/dist/esm/dnd/backend.js +148 -0
- package/dist/esm/dnd/dropOverlay.d.ts +20 -0
- package/dist/esm/dnd/dropOverlay.js +192 -0
- package/dist/esm/dnd/droptarget.d.ts +20 -6
- package/dist/esm/dnd/droptarget.js +16 -210
- package/dist/esm/dnd/pointer/index.d.ts +11 -0
- package/dist/esm/dnd/pointer/index.js +5 -0
- package/dist/esm/dnd/pointer/longPress.d.ts +32 -0
- package/dist/esm/dnd/pointer/longPress.js +127 -0
- package/dist/esm/dnd/pointer/pointerDragController.d.ts +60 -0
- package/dist/esm/dnd/pointer/pointerDragController.js +191 -0
- package/dist/esm/dnd/pointer/pointerDragSource.d.ts +61 -0
- package/dist/esm/dnd/pointer/pointerDragSource.js +171 -0
- package/dist/esm/dnd/pointer/pointerDropTarget.d.ts +39 -0
- package/dist/esm/dnd/pointer/pointerDropTarget.js +168 -0
- package/dist/esm/dnd/pointer/pointerGhost.d.ts +30 -0
- package/dist/esm/dnd/pointer/pointerGhost.js +39 -0
- package/dist/esm/dnd/pointer/types.d.ts +16 -0
- package/dist/esm/dnd/pointer/types.js +1 -0
- package/dist/esm/dockview/components/panel/content.d.ts +3 -1
- package/dist/esm/dockview/components/panel/content.js +33 -16
- package/dist/esm/dockview/components/popupService.js +34 -0
- package/dist/esm/dockview/components/tab/tab.d.ts +11 -3
- package/dist/esm/dockview/components/tab/tab.js +139 -114
- package/dist/esm/dockview/components/titlebar/tabGroupChip.d.ts +9 -2
- package/dist/esm/dockview/components/titlebar/tabGroupChip.js +15 -6
- package/dist/esm/dockview/components/titlebar/tabGroupIndicator.js +2 -2
- package/dist/esm/dockview/components/titlebar/tabGroups.d.ts +33 -5
- package/dist/esm/dockview/components/titlebar/tabGroups.js +177 -12
- package/dist/esm/dockview/components/titlebar/tabs.d.ts +38 -1
- package/dist/esm/dockview/components/titlebar/tabs.js +360 -229
- package/dist/esm/dockview/components/titlebar/tabsContainer.d.ts +5 -3
- package/dist/esm/dockview/components/titlebar/voidContainer.d.ts +6 -2
- package/dist/esm/dockview/components/titlebar/voidContainer.js +180 -26
- package/dist/esm/dockview/contextMenu.js +19 -4
- package/dist/esm/dockview/dndCapabilities.d.ts +19 -0
- package/dist/esm/dockview/dndCapabilities.js +36 -0
- package/dist/esm/dockview/dockviewComponent.d.ts +2 -0
- package/dist/esm/dockview/dockviewComponent.js +104 -41
- package/dist/esm/dockview/dockviewGroupPanelModel.d.ts +10 -5
- package/dist/esm/dockview/dockviewGroupPanelModel.js +33 -11
- package/dist/esm/dockview/dockviewPanel.js +5 -0
- package/dist/esm/dockview/dockviewPanelModel.d.ts +2 -0
- package/dist/esm/dockview/dockviewPanelModel.js +8 -0
- package/dist/esm/dockview/events.d.ts +2 -1
- package/dist/esm/dockview/events.js +1 -0
- package/dist/esm/dockview/framework.d.ts +8 -0
- package/dist/esm/dockview/options.d.ts +31 -5
- package/dist/esm/dockview/options.js +3 -0
- package/dist/esm/dom.d.ts +5 -1
- package/dist/esm/dom.js +20 -5
- package/dist/esm/index.d.ts +1 -1
- package/dist/esm/overlay/overlay.d.ts +12 -0
- package/dist/esm/overlay/overlay.js +85 -17
- package/dist/esm/paneview/draggablePaneviewPanel.d.ts +3 -1
- package/dist/esm/paneview/draggablePaneviewPanel.js +26 -20
- package/dist/esm/paneview/options.d.ts +4 -3
- package/dist/esm/popoutWindow.d.ts +2 -0
- package/dist/esm/popoutWindow.js +3 -1
- package/dist/package/main.cjs.js +2430 -936
- package/dist/package/main.cjs.min.js +2 -2
- package/dist/package/main.esm.min.mjs +2 -2
- package/dist/package/main.esm.mjs +2430 -936
- package/dist/styles/dockview.css +117 -1
- package/package.json +3 -1
- package/dist/cjs/dnd/abstractDragHandler.d.ts +0 -14
- package/dist/cjs/dnd/abstractDragHandler.js +0 -86
- package/dist/cjs/dnd/groupDragHandler.d.ts +0 -12
- package/dist/cjs/dnd/groupDragHandler.js +0 -82
- package/dist/esm/dnd/abstractDragHandler.d.ts +0 -14
- package/dist/esm/dnd/abstractDragHandler.js +0 -63
- package/dist/esm/dnd/groupDragHandler.d.ts +0 -12
- package/dist/esm/dnd/groupDragHandler.js +0 -59
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* dockview-core
|
|
3
|
-
* @version 6.
|
|
3
|
+
* @version 6.4.0
|
|
4
4
|
* @link https://github.com/mathuo/dockview
|
|
5
5
|
* @license MIT
|
|
6
6
|
*/
|
|
@@ -478,8 +478,10 @@
|
|
|
478
478
|
function quasiDefaultPrevented(event) {
|
|
479
479
|
return event[QUASI_PREVENT_DEFAULT_KEY];
|
|
480
480
|
}
|
|
481
|
-
function addStyles(document, styleSheetList) {
|
|
481
|
+
function addStyles(document, styleSheetList, options = {}) {
|
|
482
482
|
const styleSheets = Array.from(styleSheetList);
|
|
483
|
+
const { nonce } = options;
|
|
484
|
+
const resolvedNonce = typeof nonce === 'function' ? nonce(document) : nonce;
|
|
483
485
|
for (const styleSheet of styleSheets) {
|
|
484
486
|
if (styleSheet.href) {
|
|
485
487
|
const link = document.createElement('link');
|
|
@@ -487,6 +489,10 @@
|
|
|
487
489
|
link.type = styleSheet.type;
|
|
488
490
|
link.rel = 'stylesheet';
|
|
489
491
|
document.head.appendChild(link);
|
|
492
|
+
// The <link> will load and apply its rules in the target
|
|
493
|
+
// document. Reading cssRules here would duplicate them
|
|
494
|
+
// (and throws for cross-origin sheets).
|
|
495
|
+
continue;
|
|
490
496
|
}
|
|
491
497
|
let cssTexts = [];
|
|
492
498
|
try {
|
|
@@ -497,11 +503,16 @@
|
|
|
497
503
|
catch (err) {
|
|
498
504
|
console.warn('dockview: failed to access stylesheet rules due to security restrictions', err);
|
|
499
505
|
}
|
|
506
|
+
const fragment = document.createDocumentFragment();
|
|
500
507
|
for (const rule of cssTexts) {
|
|
501
508
|
const style = document.createElement('style');
|
|
509
|
+
if (resolvedNonce) {
|
|
510
|
+
style.setAttribute('nonce', resolvedNonce);
|
|
511
|
+
}
|
|
502
512
|
style.appendChild(document.createTextNode(rule));
|
|
503
|
-
|
|
513
|
+
fragment.appendChild(style);
|
|
504
514
|
}
|
|
515
|
+
document.head.appendChild(fragment);
|
|
505
516
|
}
|
|
506
517
|
}
|
|
507
518
|
function getDomNodePagePosition(domNode) {
|
|
@@ -540,7 +551,7 @@
|
|
|
540
551
|
* Should be more efficient than element.querySelectorAll("*") since there
|
|
541
552
|
* is no need to store every element in-memory using this approach
|
|
542
553
|
*/
|
|
543
|
-
function allTagsNamesInclusiveOfShadowDoms(tagNames) {
|
|
554
|
+
function allTagsNamesInclusiveOfShadowDoms(tagNames, rootNode) {
|
|
544
555
|
const iframes = [];
|
|
545
556
|
function findIframesInNode(node) {
|
|
546
557
|
if (node.nodeType === Node.ELEMENT_NODE) {
|
|
@@ -555,11 +566,15 @@
|
|
|
555
566
|
}
|
|
556
567
|
}
|
|
557
568
|
}
|
|
558
|
-
|
|
569
|
+
// Document → walk from its root element. Element → walk from itself.
|
|
570
|
+
const startEl = rootNode instanceof Document
|
|
571
|
+
? rootNode.documentElement
|
|
572
|
+
: rootNode;
|
|
573
|
+
findIframesInNode(startEl);
|
|
559
574
|
return iframes;
|
|
560
575
|
}
|
|
561
576
|
function disableIframePointEvents(rootNode = document) {
|
|
562
|
-
const iframes = allTagsNamesInclusiveOfShadowDoms(['IFRAME', 'WEBVIEW']);
|
|
577
|
+
const iframes = allTagsNamesInclusiveOfShadowDoms(['IFRAME', 'WEBVIEW'], rootNode);
|
|
563
578
|
const original = new WeakMap(); // don't hold onto HTMLElement references longer than required
|
|
564
579
|
for (const iframe of iframes) {
|
|
565
580
|
original.set(iframe, iframe.style.pointerEvents);
|
|
@@ -3979,67 +3994,6 @@
|
|
|
3979
3994
|
}
|
|
3980
3995
|
}
|
|
3981
3996
|
|
|
3982
|
-
class DragHandler extends CompositeDisposable {
|
|
3983
|
-
constructor(el, disabled) {
|
|
3984
|
-
super();
|
|
3985
|
-
this.el = el;
|
|
3986
|
-
this.disabled = disabled;
|
|
3987
|
-
this.dataDisposable = new MutableDisposable();
|
|
3988
|
-
this.pointerEventsDisposable = new MutableDisposable();
|
|
3989
|
-
this._onDragStart = new Emitter();
|
|
3990
|
-
this.onDragStart = this._onDragStart.event;
|
|
3991
|
-
this.addDisposables(this._onDragStart, this.dataDisposable, this.pointerEventsDisposable);
|
|
3992
|
-
this.configure();
|
|
3993
|
-
}
|
|
3994
|
-
setDisabled(disabled) {
|
|
3995
|
-
this.disabled = disabled;
|
|
3996
|
-
}
|
|
3997
|
-
isCancelled(_event) {
|
|
3998
|
-
return false;
|
|
3999
|
-
}
|
|
4000
|
-
configure() {
|
|
4001
|
-
this.addDisposables(this._onDragStart, addDisposableListener(this.el, 'dragstart', (event) => {
|
|
4002
|
-
if (event.defaultPrevented ||
|
|
4003
|
-
this.isCancelled(event) ||
|
|
4004
|
-
this.disabled) {
|
|
4005
|
-
event.preventDefault();
|
|
4006
|
-
return;
|
|
4007
|
-
}
|
|
4008
|
-
const iframes = disableIframePointEvents();
|
|
4009
|
-
this.pointerEventsDisposable.value = {
|
|
4010
|
-
dispose: () => {
|
|
4011
|
-
iframes.release();
|
|
4012
|
-
},
|
|
4013
|
-
};
|
|
4014
|
-
this.el.classList.add('dv-dragged');
|
|
4015
|
-
setTimeout(() => this.el.classList.remove('dv-dragged'), 0);
|
|
4016
|
-
this.dataDisposable.value = this.getData(event);
|
|
4017
|
-
this._onDragStart.fire(event);
|
|
4018
|
-
if (event.dataTransfer) {
|
|
4019
|
-
event.dataTransfer.effectAllowed = 'move';
|
|
4020
|
-
const hasData = event.dataTransfer.items.length > 0;
|
|
4021
|
-
if (!hasData) {
|
|
4022
|
-
/**
|
|
4023
|
-
* Although this is not used by dockview many third party dnd libraries will check
|
|
4024
|
-
* dataTransfer.types to determine valid drag events.
|
|
4025
|
-
*
|
|
4026
|
-
* For example: in react-dnd if dataTransfer.types is not set then the dragStart event will be cancelled
|
|
4027
|
-
* through .preventDefault(). Since this is applied globally to all drag events this would break dockviews
|
|
4028
|
-
* dnd logic. You can see the code at
|
|
4029
|
-
P * https://github.com/react-dnd/react-dnd/blob/main/packages/backend-html5/src/HTML5BackendImpl.ts#L542
|
|
4030
|
-
*/
|
|
4031
|
-
event.dataTransfer.setData('text/plain', '');
|
|
4032
|
-
}
|
|
4033
|
-
}
|
|
4034
|
-
}), addDisposableListener(this.el, 'dragend', () => {
|
|
4035
|
-
this.pointerEventsDisposable.dispose();
|
|
4036
|
-
setTimeout(() => {
|
|
4037
|
-
this.dataDisposable.dispose(); // allow the data to be read by other handlers before disposing
|
|
4038
|
-
}, 0);
|
|
4039
|
-
}));
|
|
4040
|
-
}
|
|
4041
|
-
}
|
|
4042
|
-
|
|
4043
3997
|
class DragAndDropObserver extends CompositeDisposable {
|
|
4044
3998
|
constructor(element, callbacks) {
|
|
4045
3999
|
super();
|
|
@@ -4090,48 +4044,197 @@
|
|
|
4090
4044
|
}
|
|
4091
4045
|
}
|
|
4092
4046
|
|
|
4093
|
-
|
|
4094
|
-
|
|
4095
|
-
|
|
4096
|
-
|
|
4097
|
-
|
|
4098
|
-
|
|
4099
|
-
|
|
4100
|
-
|
|
4101
|
-
|
|
4102
|
-
|
|
4103
|
-
|
|
4104
|
-
|
|
4105
|
-
|
|
4106
|
-
|
|
4107
|
-
|
|
4108
|
-
|
|
4109
|
-
|
|
4110
|
-
|
|
4111
|
-
const
|
|
4112
|
-
|
|
4113
|
-
|
|
4114
|
-
|
|
4115
|
-
|
|
4116
|
-
|
|
4117
|
-
|
|
4118
|
-
|
|
4119
|
-
|
|
4120
|
-
|
|
4121
|
-
|
|
4122
|
-
|
|
4123
|
-
|
|
4124
|
-
|
|
4125
|
-
|
|
4126
|
-
|
|
4127
|
-
|
|
4128
|
-
|
|
4129
|
-
|
|
4130
|
-
|
|
4131
|
-
|
|
4132
|
-
|
|
4133
|
-
|
|
4047
|
+
// Two render paths: in-place (dropzone appended to drop element) and
|
|
4048
|
+
// anchored (overlay rendered into an external anchor container).
|
|
4049
|
+
const DEFAULT_SIZE = { value: 50, type: 'percentage' };
|
|
4050
|
+
const SMALL_WIDTH_BOUNDARY = 100;
|
|
4051
|
+
const SMALL_HEIGHT_BOUNDARY = 100;
|
|
4052
|
+
function createOverlayElements() {
|
|
4053
|
+
const dropzone = document.createElement('div');
|
|
4054
|
+
dropzone.className = 'dv-drop-target-dropzone';
|
|
4055
|
+
const selection = document.createElement('div');
|
|
4056
|
+
selection.className = 'dv-drop-target-selection';
|
|
4057
|
+
dropzone.appendChild(selection);
|
|
4058
|
+
return { dropzone, selection };
|
|
4059
|
+
}
|
|
4060
|
+
function computeOverlayShape(quadrant, width, height, overlayModel) {
|
|
4061
|
+
var _a, _b, _c;
|
|
4062
|
+
const smallWidthBoundary = (_a = overlayModel === null || overlayModel === void 0 ? void 0 : overlayModel.smallWidthBoundary) !== null && _a !== void 0 ? _a : SMALL_WIDTH_BOUNDARY;
|
|
4063
|
+
const smallHeightBoundary = (_b = overlayModel === null || overlayModel === void 0 ? void 0 : overlayModel.smallHeightBoundary) !== null && _b !== void 0 ? _b : SMALL_HEIGHT_BOUNDARY;
|
|
4064
|
+
const isSmallX = width < smallWidthBoundary;
|
|
4065
|
+
const isSmallY = height < smallHeightBoundary;
|
|
4066
|
+
const isLeft = quadrant === 'left';
|
|
4067
|
+
const isRight = quadrant === 'right';
|
|
4068
|
+
const isTop = quadrant === 'top';
|
|
4069
|
+
const isBottom = quadrant === 'bottom';
|
|
4070
|
+
const rightClass = !isSmallX && isRight;
|
|
4071
|
+
const leftClass = !isSmallX && isLeft;
|
|
4072
|
+
const topClass = !isSmallY && isTop;
|
|
4073
|
+
const bottomClass = !isSmallY && isBottom;
|
|
4074
|
+
let size = 1;
|
|
4075
|
+
const sizeOptions = (_c = overlayModel === null || overlayModel === void 0 ? void 0 : overlayModel.size) !== null && _c !== void 0 ? _c : DEFAULT_SIZE;
|
|
4076
|
+
if (sizeOptions.type === 'percentage') {
|
|
4077
|
+
size = clamp(sizeOptions.value, 0, 100) / 100;
|
|
4078
|
+
}
|
|
4079
|
+
else {
|
|
4080
|
+
if (rightClass || leftClass) {
|
|
4081
|
+
size = clamp(0, sizeOptions.value, width) / width;
|
|
4082
|
+
}
|
|
4083
|
+
if (topClass || bottomClass) {
|
|
4084
|
+
size = clamp(0, sizeOptions.value, height) / height;
|
|
4085
|
+
}
|
|
4086
|
+
}
|
|
4087
|
+
return {
|
|
4088
|
+
isSmallX,
|
|
4089
|
+
isSmallY,
|
|
4090
|
+
isLeft,
|
|
4091
|
+
isRight,
|
|
4092
|
+
isTop,
|
|
4093
|
+
isBottom,
|
|
4094
|
+
rightClass,
|
|
4095
|
+
leftClass,
|
|
4096
|
+
topClass,
|
|
4097
|
+
bottomClass,
|
|
4098
|
+
size,
|
|
4099
|
+
};
|
|
4100
|
+
}
|
|
4101
|
+
function renderInPlaceOverlay(overlay, quadrant, width, height, overlayModel) {
|
|
4102
|
+
const shape = computeOverlayShape(quadrant, width, height, overlayModel);
|
|
4103
|
+
const { rightClass, leftClass, topClass, bottomClass, size } = shape;
|
|
4104
|
+
const box = { top: '0px', left: '0px', width: '100%', height: '100%' };
|
|
4105
|
+
if (rightClass) {
|
|
4106
|
+
box.left = `${100 * (1 - size)}%`;
|
|
4107
|
+
box.width = `${100 * size}%`;
|
|
4108
|
+
}
|
|
4109
|
+
else if (leftClass) {
|
|
4110
|
+
box.width = `${100 * size}%`;
|
|
4111
|
+
}
|
|
4112
|
+
else if (topClass) {
|
|
4113
|
+
box.height = `${100 * size}%`;
|
|
4114
|
+
}
|
|
4115
|
+
else if (bottomClass) {
|
|
4116
|
+
box.top = `${100 * (1 - size)}%`;
|
|
4117
|
+
box.height = `${100 * size}%`;
|
|
4118
|
+
}
|
|
4119
|
+
if (shape.isSmallX && shape.isLeft) {
|
|
4120
|
+
box.width = '4px';
|
|
4121
|
+
}
|
|
4122
|
+
if (shape.isSmallX && shape.isRight) {
|
|
4123
|
+
box.left = `${width - 4}px`;
|
|
4124
|
+
box.width = '4px';
|
|
4125
|
+
}
|
|
4126
|
+
if (shape.isSmallY && shape.isTop) {
|
|
4127
|
+
box.height = '4px';
|
|
4128
|
+
}
|
|
4129
|
+
if (shape.isSmallY && shape.isBottom) {
|
|
4130
|
+
box.top = `${height - 4}px`;
|
|
4131
|
+
box.height = '4px';
|
|
4132
|
+
}
|
|
4133
|
+
overlay.style.top = box.top;
|
|
4134
|
+
overlay.style.left = box.left;
|
|
4135
|
+
overlay.style.width = box.width;
|
|
4136
|
+
overlay.style.height = box.height;
|
|
4137
|
+
overlay.style.visibility = 'visible';
|
|
4138
|
+
if (!overlay.style.transform || overlay.style.transform === '') {
|
|
4139
|
+
overlay.style.transform = 'translate3d(0, 0, 0)';
|
|
4140
|
+
}
|
|
4141
|
+
const isLine = (shape.isSmallX && (shape.isLeft || shape.isRight)) ||
|
|
4142
|
+
(shape.isSmallY && (shape.isTop || shape.isBottom));
|
|
4143
|
+
toggleClass(overlay, 'dv-drop-target-small-vertical', shape.isSmallY);
|
|
4144
|
+
toggleClass(overlay, 'dv-drop-target-small-horizontal', shape.isSmallX);
|
|
4145
|
+
toggleClass(overlay, 'dv-drop-target-selection-line', isLine);
|
|
4146
|
+
toggleClass(overlay, 'dv-drop-target-left', shape.isLeft);
|
|
4147
|
+
toggleClass(overlay, 'dv-drop-target-right', shape.isRight);
|
|
4148
|
+
toggleClass(overlay, 'dv-drop-target-top', shape.isTop);
|
|
4149
|
+
toggleClass(overlay, 'dv-drop-target-bottom', shape.isBottom);
|
|
4150
|
+
toggleClass(overlay, 'dv-drop-target-center', quadrant === 'center');
|
|
4151
|
+
}
|
|
4152
|
+
function checkAnchoredBoundsChanged(overlay, bounds) {
|
|
4153
|
+
const topPx = `${Math.round(bounds.top)}px`;
|
|
4154
|
+
const leftPx = `${Math.round(bounds.left)}px`;
|
|
4155
|
+
const widthPx = `${Math.round(bounds.width)}px`;
|
|
4156
|
+
const heightPx = `${Math.round(bounds.height)}px`;
|
|
4157
|
+
return (overlay.style.top !== topPx ||
|
|
4158
|
+
overlay.style.left !== leftPx ||
|
|
4159
|
+
overlay.style.width !== widthPx ||
|
|
4160
|
+
overlay.style.height !== heightPx);
|
|
4161
|
+
}
|
|
4162
|
+
function applyAnchoredBounds(overlay, bounds) {
|
|
4163
|
+
overlay.style.top = `${Math.round(bounds.top)}px`;
|
|
4164
|
+
overlay.style.left = `${Math.round(bounds.left)}px`;
|
|
4165
|
+
overlay.style.width = `${Math.round(bounds.width)}px`;
|
|
4166
|
+
overlay.style.height = `${Math.round(bounds.height)}px`;
|
|
4167
|
+
overlay.style.visibility = 'visible';
|
|
4168
|
+
if (!overlay.style.transform || overlay.style.transform === '') {
|
|
4169
|
+
overlay.style.transform = 'translate3d(0, 0, 0)';
|
|
4170
|
+
}
|
|
4171
|
+
}
|
|
4172
|
+
/** `boundsChanged: false` lets callers skip redundant work on tight drag loops. */
|
|
4173
|
+
function renderAnchoredOverlay(args) {
|
|
4174
|
+
const shape = computeOverlayShape(args.quadrant, args.width, args.height, args.overlayModel);
|
|
4175
|
+
const { rightClass, leftClass, topClass, bottomClass, size } = shape;
|
|
4176
|
+
const elBox = args.outlineElement.getBoundingClientRect();
|
|
4177
|
+
const ta = args.targetModel.getElements(undefined, args.outlineElement);
|
|
4178
|
+
const el = ta.root;
|
|
4179
|
+
const overlay = ta.overlay;
|
|
4180
|
+
const bigbox = el.getBoundingClientRect();
|
|
4181
|
+
const rootTop = elBox.top - bigbox.top;
|
|
4182
|
+
const rootLeft = elBox.left - bigbox.left;
|
|
4183
|
+
const box = {
|
|
4184
|
+
top: rootTop,
|
|
4185
|
+
left: rootLeft,
|
|
4186
|
+
width: args.width,
|
|
4187
|
+
height: args.height,
|
|
4188
|
+
};
|
|
4189
|
+
if (rightClass) {
|
|
4190
|
+
box.left = rootLeft + args.width * (1 - size);
|
|
4191
|
+
box.width = args.width * size;
|
|
4192
|
+
}
|
|
4193
|
+
else if (leftClass) {
|
|
4194
|
+
box.width = args.width * size;
|
|
4195
|
+
}
|
|
4196
|
+
else if (topClass) {
|
|
4197
|
+
box.height = args.height * size;
|
|
4198
|
+
}
|
|
4199
|
+
else if (bottomClass) {
|
|
4200
|
+
box.top = rootTop + args.height * (1 - size);
|
|
4201
|
+
box.height = args.height * size;
|
|
4202
|
+
}
|
|
4203
|
+
if (shape.isSmallX && shape.isLeft) {
|
|
4204
|
+
box.width = 4;
|
|
4205
|
+
}
|
|
4206
|
+
if (shape.isSmallX && shape.isRight) {
|
|
4207
|
+
box.left = rootLeft + args.width - 4;
|
|
4208
|
+
box.width = 4;
|
|
4209
|
+
}
|
|
4210
|
+
if (shape.isSmallY && shape.isTop) {
|
|
4211
|
+
box.height = 4;
|
|
4212
|
+
}
|
|
4213
|
+
if (shape.isSmallY && shape.isBottom) {
|
|
4214
|
+
box.top = rootTop + args.height - 4;
|
|
4215
|
+
box.height = 4;
|
|
4216
|
+
}
|
|
4217
|
+
if (!checkAnchoredBoundsChanged(overlay, box)) {
|
|
4218
|
+
return { boundsChanged: false, targetChanged: ta.changed };
|
|
4219
|
+
}
|
|
4220
|
+
applyAnchoredBounds(overlay, box);
|
|
4221
|
+
overlay.className = `dv-drop-target-anchor${args.className ? ` ${args.className}` : ''}`;
|
|
4222
|
+
toggleClass(overlay, 'dv-drop-target-left', shape.isLeft);
|
|
4223
|
+
toggleClass(overlay, 'dv-drop-target-right', shape.isRight);
|
|
4224
|
+
toggleClass(overlay, 'dv-drop-target-top', shape.isTop);
|
|
4225
|
+
toggleClass(overlay, 'dv-drop-target-bottom', shape.isBottom);
|
|
4226
|
+
toggleClass(overlay, 'dv-drop-target-anchor-line', (shape.isSmallX && (shape.isLeft || shape.isRight)) ||
|
|
4227
|
+
(shape.isSmallY && (shape.isTop || shape.isBottom)));
|
|
4228
|
+
toggleClass(overlay, 'dv-drop-target-center', args.quadrant === 'center');
|
|
4229
|
+
if (ta.changed) {
|
|
4230
|
+
toggleClass(overlay, 'dv-drop-target-anchor-container-changed', true);
|
|
4231
|
+
setTimeout(() => {
|
|
4232
|
+
toggleClass(overlay, 'dv-drop-target-anchor-container-changed', false);
|
|
4233
|
+
}, 10);
|
|
4234
|
+
}
|
|
4235
|
+
return { boundsChanged: true, targetChanged: ta.changed };
|
|
4134
4236
|
}
|
|
4237
|
+
|
|
4135
4238
|
class WillShowOverlayEvent extends DockviewEvent {
|
|
4136
4239
|
get nativeEvent() {
|
|
4137
4240
|
return this.options.nativeEvent;
|
|
@@ -4176,16 +4279,10 @@
|
|
|
4176
4279
|
throw new Error(`invalid position '${position}'`);
|
|
4177
4280
|
}
|
|
4178
4281
|
}
|
|
4179
|
-
const DEFAULT_ACTIVATION_SIZE = {
|
|
4282
|
+
const DEFAULT_ACTIVATION_SIZE$1 = {
|
|
4180
4283
|
value: 20,
|
|
4181
4284
|
type: 'percentage',
|
|
4182
4285
|
};
|
|
4183
|
-
const DEFAULT_SIZE = {
|
|
4184
|
-
value: 50,
|
|
4185
|
-
type: 'percentage',
|
|
4186
|
-
};
|
|
4187
|
-
const SMALL_WIDTH_BOUNDARY = 100;
|
|
4188
|
-
const SMALL_HEIGHT_BOUNDARY = 100;
|
|
4189
4286
|
class Droptarget extends CompositeDisposable {
|
|
4190
4287
|
get disabled() {
|
|
4191
4288
|
return this._disabled;
|
|
@@ -4266,20 +4363,12 @@
|
|
|
4266
4363
|
this.markAsUsed(e);
|
|
4267
4364
|
if (overrideTarget) ;
|
|
4268
4365
|
else if (!this.targetElement) {
|
|
4269
|
-
|
|
4270
|
-
this.targetElement
|
|
4271
|
-
this.overlayElement =
|
|
4272
|
-
this.overlayElement.className = 'dv-drop-target-selection';
|
|
4366
|
+
const els = createOverlayElements();
|
|
4367
|
+
this.targetElement = els.dropzone;
|
|
4368
|
+
this.overlayElement = els.selection;
|
|
4273
4369
|
this._state = 'center';
|
|
4274
|
-
this.targetElement.appendChild(this.overlayElement);
|
|
4275
4370
|
target.classList.add('dv-drop-target');
|
|
4276
4371
|
target.append(this.targetElement);
|
|
4277
|
-
// this.overlayElement.style.opacity = '0';
|
|
4278
|
-
// requestAnimationFrame(() => {
|
|
4279
|
-
// if (this.overlayElement) {
|
|
4280
|
-
// this.overlayElement.style.opacity = '';
|
|
4281
|
-
// }
|
|
4282
|
-
// });
|
|
4283
4372
|
}
|
|
4284
4373
|
this.toggleClasses(quadrant, width, height);
|
|
4285
4374
|
this._state = quadrant;
|
|
@@ -4349,166 +4438,29 @@
|
|
|
4349
4438
|
return typeof value === 'boolean' && value;
|
|
4350
4439
|
}
|
|
4351
4440
|
toggleClasses(quadrant, width, height) {
|
|
4352
|
-
var _a, _b, _c, _d, _e
|
|
4441
|
+
var _a, _b, _c, _d, _e;
|
|
4353
4442
|
const target = (_b = (_a = this.options).getOverrideTarget) === null || _b === void 0 ? void 0 : _b.call(_a);
|
|
4354
|
-
if (!target && !this.overlayElement) {
|
|
4355
|
-
return;
|
|
4356
|
-
}
|
|
4357
|
-
const smallWidthBoundary = (_d = (_c = this.options.overlayModel) === null || _c === void 0 ? void 0 : _c.smallWidthBoundary) !== null && _d !== void 0 ? _d : SMALL_WIDTH_BOUNDARY;
|
|
4358
|
-
const smallHeightBoundary = (_f = (_e = this.options.overlayModel) === null || _e === void 0 ? void 0 : _e.smallHeightBoundary) !== null && _f !== void 0 ? _f : SMALL_HEIGHT_BOUNDARY;
|
|
4359
|
-
const isSmallX = width < smallWidthBoundary;
|
|
4360
|
-
const isSmallY = height < smallHeightBoundary;
|
|
4361
|
-
const isLeft = quadrant === 'left';
|
|
4362
|
-
const isRight = quadrant === 'right';
|
|
4363
|
-
const isTop = quadrant === 'top';
|
|
4364
|
-
const isBottom = quadrant === 'bottom';
|
|
4365
|
-
const rightClass = !isSmallX && isRight;
|
|
4366
|
-
const leftClass = !isSmallX && isLeft;
|
|
4367
|
-
const topClass = !isSmallY && isTop;
|
|
4368
|
-
const bottomClass = !isSmallY && isBottom;
|
|
4369
|
-
let size = 1;
|
|
4370
|
-
const sizeOptions = (_h = (_g = this.options.overlayModel) === null || _g === void 0 ? void 0 : _g.size) !== null && _h !== void 0 ? _h : DEFAULT_SIZE;
|
|
4371
|
-
if (sizeOptions.type === 'percentage') {
|
|
4372
|
-
size = clamp(sizeOptions.value, 0, 100) / 100;
|
|
4373
|
-
}
|
|
4374
|
-
else {
|
|
4375
|
-
if (rightClass || leftClass) {
|
|
4376
|
-
size = clamp(0, sizeOptions.value, width) / width;
|
|
4377
|
-
}
|
|
4378
|
-
if (topClass || bottomClass) {
|
|
4379
|
-
size = clamp(0, sizeOptions.value, height) / height;
|
|
4380
|
-
}
|
|
4381
|
-
}
|
|
4382
4443
|
if (target) {
|
|
4383
|
-
const outlineEl = (
|
|
4384
|
-
|
|
4385
|
-
|
|
4386
|
-
|
|
4387
|
-
|
|
4388
|
-
|
|
4389
|
-
|
|
4390
|
-
|
|
4391
|
-
|
|
4392
|
-
|
|
4393
|
-
left: rootLeft,
|
|
4394
|
-
width: width,
|
|
4395
|
-
height: height,
|
|
4396
|
-
};
|
|
4397
|
-
if (rightClass) {
|
|
4398
|
-
box.left = rootLeft + width * (1 - size);
|
|
4399
|
-
box.width = width * size;
|
|
4400
|
-
}
|
|
4401
|
-
else if (leftClass) {
|
|
4402
|
-
box.width = width * size;
|
|
4403
|
-
}
|
|
4404
|
-
else if (topClass) {
|
|
4405
|
-
box.height = height * size;
|
|
4406
|
-
}
|
|
4407
|
-
else if (bottomClass) {
|
|
4408
|
-
box.top = rootTop + height * (1 - size);
|
|
4409
|
-
box.height = height * size;
|
|
4410
|
-
}
|
|
4411
|
-
if (isSmallX && isLeft) {
|
|
4412
|
-
box.width = 4;
|
|
4413
|
-
}
|
|
4414
|
-
if (isSmallX && isRight) {
|
|
4415
|
-
box.left = rootLeft + width - 4;
|
|
4416
|
-
box.width = 4;
|
|
4417
|
-
}
|
|
4418
|
-
if (isSmallY && isTop) {
|
|
4419
|
-
box.height = 4;
|
|
4420
|
-
}
|
|
4421
|
-
if (isSmallY && isBottom) {
|
|
4422
|
-
box.top = rootTop + height - 4;
|
|
4423
|
-
box.height = 4;
|
|
4424
|
-
}
|
|
4425
|
-
// Use GPU-optimized bounds checking and setting
|
|
4426
|
-
if (!checkBoundsChanged(overlay, box)) {
|
|
4427
|
-
return;
|
|
4428
|
-
}
|
|
4429
|
-
setGPUOptimizedBounds(overlay, box);
|
|
4430
|
-
overlay.className = `dv-drop-target-anchor${this.options.className ? ` ${this.options.className}` : ''}`;
|
|
4431
|
-
toggleClass(overlay, 'dv-drop-target-left', isLeft);
|
|
4432
|
-
toggleClass(overlay, 'dv-drop-target-right', isRight);
|
|
4433
|
-
toggleClass(overlay, 'dv-drop-target-top', isTop);
|
|
4434
|
-
toggleClass(overlay, 'dv-drop-target-bottom', isBottom);
|
|
4435
|
-
toggleClass(overlay, 'dv-drop-target-anchor-line', (isSmallX && (isLeft || isRight)) ||
|
|
4436
|
-
(isSmallY && (isTop || isBottom)));
|
|
4437
|
-
toggleClass(overlay, 'dv-drop-target-center', quadrant === 'center');
|
|
4438
|
-
if (ta.changed) {
|
|
4439
|
-
toggleClass(overlay, 'dv-drop-target-anchor-container-changed', true);
|
|
4440
|
-
setTimeout(() => {
|
|
4441
|
-
toggleClass(overlay, 'dv-drop-target-anchor-container-changed', false);
|
|
4442
|
-
}, 10);
|
|
4443
|
-
}
|
|
4444
|
+
const outlineEl = (_e = (_d = (_c = this.options).getOverlayOutline) === null || _d === void 0 ? void 0 : _d.call(_c)) !== null && _e !== void 0 ? _e : this.element;
|
|
4445
|
+
renderAnchoredOverlay({
|
|
4446
|
+
outlineElement: outlineEl,
|
|
4447
|
+
targetModel: target,
|
|
4448
|
+
quadrant,
|
|
4449
|
+
width,
|
|
4450
|
+
height,
|
|
4451
|
+
overlayModel: this.options.overlayModel,
|
|
4452
|
+
className: this.options.className,
|
|
4453
|
+
});
|
|
4444
4454
|
return;
|
|
4445
4455
|
}
|
|
4446
4456
|
if (!this.overlayElement) {
|
|
4447
4457
|
return;
|
|
4448
4458
|
}
|
|
4449
|
-
|
|
4450
|
-
/**
|
|
4451
|
-
* You can also achieve the overlay placement using the transform CSS property
|
|
4452
|
-
* to translate and scale the element however this has the undesired effect of
|
|
4453
|
-
* 'skewing' the element. Comment left here for anybody that ever revisits this.
|
|
4454
|
-
*
|
|
4455
|
-
* @see https://developer.mozilla.org/en-US/docs/Web/CSS/transform
|
|
4456
|
-
*
|
|
4457
|
-
* right
|
|
4458
|
-
* translateX(${100 * (1 - size) / 2}%) scaleX(${scale})
|
|
4459
|
-
*
|
|
4460
|
-
* left
|
|
4461
|
-
* translateX(-${100 * (1 - size) / 2}%) scaleX(${scale})
|
|
4462
|
-
*
|
|
4463
|
-
* top
|
|
4464
|
-
* translateY(-${100 * (1 - size) / 2}%) scaleY(${scale})
|
|
4465
|
-
*
|
|
4466
|
-
* bottom
|
|
4467
|
-
* translateY(${100 * (1 - size) / 2}%) scaleY(${scale})
|
|
4468
|
-
*/
|
|
4469
|
-
if (rightClass) {
|
|
4470
|
-
box.left = `${100 * (1 - size)}%`;
|
|
4471
|
-
box.width = `${100 * size}%`;
|
|
4472
|
-
}
|
|
4473
|
-
else if (leftClass) {
|
|
4474
|
-
box.width = `${100 * size}%`;
|
|
4475
|
-
}
|
|
4476
|
-
else if (topClass) {
|
|
4477
|
-
box.height = `${100 * size}%`;
|
|
4478
|
-
}
|
|
4479
|
-
else if (bottomClass) {
|
|
4480
|
-
box.top = `${100 * (1 - size)}%`;
|
|
4481
|
-
box.height = `${100 * size}%`;
|
|
4482
|
-
}
|
|
4483
|
-
if (isSmallX && isLeft) {
|
|
4484
|
-
box.width = '4px';
|
|
4485
|
-
}
|
|
4486
|
-
if (isSmallX && isRight) {
|
|
4487
|
-
box.left = `${width - 4}px`;
|
|
4488
|
-
box.width = '4px';
|
|
4489
|
-
}
|
|
4490
|
-
if (isSmallY && isTop) {
|
|
4491
|
-
box.height = '4px';
|
|
4492
|
-
}
|
|
4493
|
-
if (isSmallY && isBottom) {
|
|
4494
|
-
box.top = `${height - 4}px`;
|
|
4495
|
-
box.height = '4px';
|
|
4496
|
-
}
|
|
4497
|
-
setGPUOptimizedBoundsFromStrings(this.overlayElement, box);
|
|
4498
|
-
const isLine = (isSmallX && (isLeft || isRight)) ||
|
|
4499
|
-
(isSmallY && (isTop || isBottom));
|
|
4500
|
-
toggleClass(this.overlayElement, 'dv-drop-target-small-vertical', isSmallY);
|
|
4501
|
-
toggleClass(this.overlayElement, 'dv-drop-target-small-horizontal', isSmallX);
|
|
4502
|
-
toggleClass(this.overlayElement, 'dv-drop-target-selection-line', isLine);
|
|
4503
|
-
toggleClass(this.overlayElement, 'dv-drop-target-left', isLeft);
|
|
4504
|
-
toggleClass(this.overlayElement, 'dv-drop-target-right', isRight);
|
|
4505
|
-
toggleClass(this.overlayElement, 'dv-drop-target-top', isTop);
|
|
4506
|
-
toggleClass(this.overlayElement, 'dv-drop-target-bottom', isBottom);
|
|
4507
|
-
toggleClass(this.overlayElement, 'dv-drop-target-center', quadrant === 'center');
|
|
4459
|
+
renderInPlaceOverlay(this.overlayElement, quadrant, width, height, this.options.overlayModel);
|
|
4508
4460
|
}
|
|
4509
4461
|
calculateQuadrant(overlayType, x, y, width, height) {
|
|
4510
4462
|
var _a, _b;
|
|
4511
|
-
const activationSizeOptions = (_b = (_a = this.options.overlayModel) === null || _a === void 0 ? void 0 : _a.activationSize) !== null && _b !== void 0 ? _b : DEFAULT_ACTIVATION_SIZE;
|
|
4463
|
+
const activationSizeOptions = (_b = (_a = this.options.overlayModel) === null || _a === void 0 ? void 0 : _a.activationSize) !== null && _b !== void 0 ? _b : DEFAULT_ACTIVATION_SIZE$1;
|
|
4512
4464
|
const isPercentage = activationSizeOptions.type === 'percentage';
|
|
4513
4465
|
if (isPercentage) {
|
|
4514
4466
|
return calculateQuadrantAsPercentage(overlayType, x, y, width, height, activationSizeOptions.value);
|
|
@@ -4566,129 +4518,846 @@
|
|
|
4566
4518
|
return 'center';
|
|
4567
4519
|
}
|
|
4568
4520
|
|
|
4569
|
-
|
|
4570
|
-
|
|
4571
|
-
|
|
4572
|
-
|
|
4573
|
-
|
|
4574
|
-
|
|
4575
|
-
|
|
4576
|
-
|
|
4577
|
-
|
|
4578
|
-
|
|
4579
|
-
|
|
4580
|
-
|
|
4581
|
-
class PaneviewUnhandledDragOverEvent extends AcceptableEvent {
|
|
4582
|
-
constructor(nativeEvent, position, getData, panel) {
|
|
4583
|
-
super();
|
|
4584
|
-
this.nativeEvent = nativeEvent;
|
|
4585
|
-
this.position = position;
|
|
4586
|
-
this.getData = getData;
|
|
4587
|
-
this.panel = panel;
|
|
4588
|
-
}
|
|
4521
|
+
function addGhostImage(dataTransfer, ghostElement, options) {
|
|
4522
|
+
var _a, _b;
|
|
4523
|
+
// class dockview provides to force ghost image to be drawn on a different layer and prevent weird rendering issues
|
|
4524
|
+
addClasses(ghostElement, 'dv-dragged');
|
|
4525
|
+
// move the element off-screen initially otherwise it may in some cases be rendered at (0,0) momentarily
|
|
4526
|
+
ghostElement.style.top = '-9999px';
|
|
4527
|
+
document.body.appendChild(ghostElement);
|
|
4528
|
+
dataTransfer.setDragImage(ghostElement, (_a = options === null || options === void 0 ? void 0 : options.x) !== null && _a !== void 0 ? _a : 0, (_b = options === null || options === void 0 ? void 0 : options.y) !== null && _b !== void 0 ? _b : 0);
|
|
4529
|
+
setTimeout(() => {
|
|
4530
|
+
removeClasses(ghostElement, 'dv-dragged');
|
|
4531
|
+
ghostElement.remove();
|
|
4532
|
+
}, 0);
|
|
4589
4533
|
}
|
|
4590
4534
|
|
|
4591
|
-
class WillFocusEvent extends DockviewEvent {
|
|
4592
|
-
constructor() {
|
|
4593
|
-
super();
|
|
4594
|
-
}
|
|
4595
|
-
}
|
|
4596
4535
|
/**
|
|
4597
|
-
*
|
|
4536
|
+
* Singleton — only one pointer-driven drag active at a time.
|
|
4537
|
+
*
|
|
4538
|
+
* State is shared across every Dockview instance on the page. Targets
|
|
4539
|
+
* from instance B receive hit-tests from drags originating in instance A;
|
|
4540
|
+
* that's intentional for cross-instance drops since `LocalSelectionTransfer`
|
|
4541
|
+
* is also process-wide. The corollary is that every Tabs subscriber to
|
|
4542
|
+
* `onDragMove` fires for every pointer drag globally — each subscriber
|
|
4543
|
+
* hit-tests against its own DOM, so this is O(N) per pointermove where N
|
|
4544
|
+
* is the number of registered listeners across all instances.
|
|
4598
4545
|
*/
|
|
4599
|
-
class
|
|
4600
|
-
|
|
4601
|
-
|
|
4602
|
-
|
|
4603
|
-
|
|
4604
|
-
return
|
|
4605
|
-
}
|
|
4606
|
-
get isVisible() {
|
|
4607
|
-
return this._isVisible;
|
|
4608
|
-
}
|
|
4609
|
-
get width() {
|
|
4610
|
-
return this._width;
|
|
4611
|
-
}
|
|
4612
|
-
get height() {
|
|
4613
|
-
return this._height;
|
|
4546
|
+
class PointerDragController extends CompositeDisposable {
|
|
4547
|
+
static getInstance() {
|
|
4548
|
+
if (!PointerDragController._instance) {
|
|
4549
|
+
PointerDragController._instance = new PointerDragController();
|
|
4550
|
+
}
|
|
4551
|
+
return PointerDragController._instance;
|
|
4614
4552
|
}
|
|
4615
|
-
constructor(
|
|
4553
|
+
constructor() {
|
|
4616
4554
|
super();
|
|
4617
|
-
this.
|
|
4618
|
-
|
|
4619
|
-
this.
|
|
4620
|
-
this.
|
|
4621
|
-
this.
|
|
4622
|
-
this.
|
|
4623
|
-
this.
|
|
4624
|
-
this.
|
|
4625
|
-
this.
|
|
4626
|
-
this.
|
|
4627
|
-
this.onDidDimensionsChange = this._onDidDimensionChange.event;
|
|
4628
|
-
this._onDidChangeFocus = new Emitter();
|
|
4629
|
-
this.onDidFocusChange = this._onDidChangeFocus.event;
|
|
4630
|
-
//
|
|
4631
|
-
this._onWillFocus = new Emitter();
|
|
4632
|
-
this.onWillFocus = this._onWillFocus.event;
|
|
4633
|
-
//
|
|
4634
|
-
this._onDidVisibilityChange = new Emitter();
|
|
4635
|
-
this.onDidVisibilityChange = this._onDidVisibilityChange.event;
|
|
4636
|
-
this._onWillVisibilityChange = new Emitter();
|
|
4637
|
-
this.onWillVisibilityChange = this._onWillVisibilityChange.event;
|
|
4638
|
-
this._onDidActiveChange = new Emitter();
|
|
4639
|
-
this.onDidActiveChange = this._onDidActiveChange.event;
|
|
4640
|
-
this._onActiveChange = new Emitter();
|
|
4641
|
-
this.onActiveChange = this._onActiveChange.event;
|
|
4642
|
-
this._onDidParametersChange = new Emitter();
|
|
4643
|
-
this.onDidParametersChange = this._onDidParametersChange.event;
|
|
4644
|
-
this.addDisposables(this.onDidFocusChange((event) => {
|
|
4645
|
-
this._isFocused = event.isFocused;
|
|
4646
|
-
}), this.onDidActiveChange((event) => {
|
|
4647
|
-
this._isActive = event.isActive;
|
|
4648
|
-
}), this.onDidVisibilityChange((event) => {
|
|
4649
|
-
this._isVisible = event.isVisible;
|
|
4650
|
-
}), this.onDidDimensionsChange((event) => {
|
|
4651
|
-
this._width = event.width;
|
|
4652
|
-
this._height = event.height;
|
|
4653
|
-
}), this.panelUpdatesDisposable, this._onDidDimensionChange, this._onDidChangeFocus, this._onDidVisibilityChange, this._onDidActiveChange, this._onWillFocus, this._onActiveChange, this._onWillFocus, this._onWillVisibilityChange, this._onDidParametersChange);
|
|
4555
|
+
this._targets = new Set();
|
|
4556
|
+
/** Kept in sync with `_targets` so hit-testing is allocation-free. */
|
|
4557
|
+
this._targetByElement = new Map();
|
|
4558
|
+
this._onDragStart = new Emitter();
|
|
4559
|
+
this.onDragStart = this._onDragStart.event;
|
|
4560
|
+
this._onDragMove = new Emitter();
|
|
4561
|
+
this.onDragMove = this._onDragMove.event;
|
|
4562
|
+
this._onDragEnd = new Emitter();
|
|
4563
|
+
this.onDragEnd = this._onDragEnd.event;
|
|
4564
|
+
this.addDisposables(this._onDragStart, this._onDragMove, this._onDragEnd);
|
|
4654
4565
|
}
|
|
4655
|
-
|
|
4656
|
-
return this.
|
|
4566
|
+
get active() {
|
|
4567
|
+
return this._active;
|
|
4657
4568
|
}
|
|
4658
|
-
|
|
4659
|
-
this.
|
|
4660
|
-
|
|
4661
|
-
|
|
4662
|
-
|
|
4663
|
-
|
|
4569
|
+
registerTarget(target) {
|
|
4570
|
+
this._targets.add(target);
|
|
4571
|
+
this._targetByElement.set(target.element, target);
|
|
4572
|
+
return {
|
|
4573
|
+
dispose: () => {
|
|
4574
|
+
this._targets.delete(target);
|
|
4575
|
+
if (this._targetByElement.get(target.element) === target) {
|
|
4576
|
+
this._targetByElement.delete(target.element);
|
|
4577
|
+
}
|
|
4578
|
+
if (this._currentTarget === target) {
|
|
4579
|
+
this._currentTarget = undefined;
|
|
4580
|
+
}
|
|
4581
|
+
},
|
|
4582
|
+
};
|
|
4583
|
+
}
|
|
4584
|
+
beginDrag(args) {
|
|
4585
|
+
var _a, _b, _c;
|
|
4586
|
+
if (this._active) {
|
|
4587
|
+
this.cancel();
|
|
4588
|
+
}
|
|
4589
|
+
const { pointerEvent, source } = args;
|
|
4590
|
+
// Call `getData()` before mutating controller state — a throw
|
|
4591
|
+
// here would otherwise leave `_active` populated with no window
|
|
4592
|
+
// listeners installed, blocking every subsequent drag.
|
|
4593
|
+
const dataDisposable = args.getData();
|
|
4594
|
+
this._active = {
|
|
4595
|
+
pointerId: pointerEvent.pointerId,
|
|
4596
|
+
startX: pointerEvent.clientX,
|
|
4597
|
+
startY: pointerEvent.clientY,
|
|
4598
|
+
source,
|
|
4599
|
+
};
|
|
4600
|
+
this._onDragMoveCallback = args.onDragMove;
|
|
4601
|
+
this._onDragEndCallback = args.onDragEnd;
|
|
4602
|
+
this._dataDisposable = dataDisposable;
|
|
4603
|
+
this._ghost = args.ghost;
|
|
4604
|
+
// Iframes capture pointermove once the cursor crosses into them,
|
|
4605
|
+
// which would freeze the drag from the parent window's POV.
|
|
4606
|
+
this._iframeShield = disableIframePointEvents((_a = source.ownerDocument) !== null && _a !== void 0 ? _a : document);
|
|
4607
|
+
const startEvent = {
|
|
4608
|
+
clientX: pointerEvent.clientX,
|
|
4609
|
+
clientY: pointerEvent.clientY,
|
|
4610
|
+
pointerEvent,
|
|
4611
|
+
};
|
|
4612
|
+
this._onDragStart.fire(startEvent);
|
|
4613
|
+
// Source's owning window — popout drags fire on their own window,
|
|
4614
|
+
// not the main one.
|
|
4615
|
+
const targetWindow = (_c = (_b = source.ownerDocument) === null || _b === void 0 ? void 0 : _b.defaultView) !== null && _c !== void 0 ? _c : window;
|
|
4616
|
+
this._moveListener = addDisposableListener(targetWindow, 'pointermove', (e) => {
|
|
4617
|
+
if (!this._active || e.pointerId !== this._active.pointerId) {
|
|
4618
|
+
return;
|
|
4619
|
+
}
|
|
4620
|
+
this._handleMove(e);
|
|
4621
|
+
});
|
|
4622
|
+
this._upListener = addDisposableListener(targetWindow, 'pointerup', (e) => {
|
|
4623
|
+
if (!this._active || e.pointerId !== this._active.pointerId) {
|
|
4624
|
+
return;
|
|
4625
|
+
}
|
|
4626
|
+
this._handleEnd(e, true);
|
|
4627
|
+
});
|
|
4628
|
+
this._cancelListener = addDisposableListener(targetWindow, 'pointercancel', (e) => {
|
|
4629
|
+
if (!this._active || e.pointerId !== this._active.pointerId) {
|
|
4630
|
+
return;
|
|
4631
|
+
}
|
|
4632
|
+
this._handleEnd(e, false);
|
|
4664
4633
|
});
|
|
4665
4634
|
}
|
|
4666
|
-
|
|
4667
|
-
|
|
4635
|
+
cancel() {
|
|
4636
|
+
var _a, _b;
|
|
4637
|
+
if (!this._active) {
|
|
4638
|
+
return;
|
|
4639
|
+
}
|
|
4640
|
+
(_a = this._currentTarget) === null || _a === void 0 ? void 0 : _a.handleDragLeave();
|
|
4641
|
+
this._teardown();
|
|
4642
|
+
(_b = this._dataDisposable) === null || _b === void 0 ? void 0 : _b.dispose();
|
|
4643
|
+
this._dataDisposable = undefined;
|
|
4668
4644
|
}
|
|
4669
|
-
|
|
4670
|
-
|
|
4645
|
+
_findTargetUnder(x, y) {
|
|
4646
|
+
var _a, _b;
|
|
4647
|
+
// `elementsFromPoint` is topmost-first; walk up to find the closest
|
|
4648
|
+
// registered ancestor (so a tab beats the layout-root that contains it).
|
|
4649
|
+
// Use the source's owning document so popout drags hit their own targets.
|
|
4650
|
+
const sourceDoc = (_b = (_a = this._active) === null || _a === void 0 ? void 0 : _a.source.ownerDocument) !== null && _b !== void 0 ? _b : document;
|
|
4651
|
+
const elements = sourceDoc.elementsFromPoint(x, y);
|
|
4652
|
+
for (const el of elements) {
|
|
4653
|
+
let current = el;
|
|
4654
|
+
while (current) {
|
|
4655
|
+
const target = this._targetByElement.get(current);
|
|
4656
|
+
if (target) {
|
|
4657
|
+
return target;
|
|
4658
|
+
}
|
|
4659
|
+
current = current.parentElement;
|
|
4660
|
+
}
|
|
4661
|
+
}
|
|
4662
|
+
return undefined;
|
|
4671
4663
|
}
|
|
4672
|
-
|
|
4673
|
-
|
|
4664
|
+
_handleMove(e) {
|
|
4665
|
+
var _a, _b, _c;
|
|
4666
|
+
(_a = this._ghost) === null || _a === void 0 ? void 0 : _a.update(e.clientX, e.clientY);
|
|
4667
|
+
const dragEvent = {
|
|
4668
|
+
clientX: e.clientX,
|
|
4669
|
+
clientY: e.clientY,
|
|
4670
|
+
pointerEvent: e,
|
|
4671
|
+
};
|
|
4672
|
+
const newTarget = this._findTargetUnder(e.clientX, e.clientY);
|
|
4673
|
+
if (newTarget !== this._currentTarget) {
|
|
4674
|
+
(_b = this._currentTarget) === null || _b === void 0 ? void 0 : _b.handleDragLeave();
|
|
4675
|
+
this._currentTarget = newTarget;
|
|
4676
|
+
}
|
|
4677
|
+
if (newTarget) {
|
|
4678
|
+
newTarget.handleDragOver(dragEvent);
|
|
4679
|
+
}
|
|
4680
|
+
(_c = this._onDragMoveCallback) === null || _c === void 0 ? void 0 : _c.call(this, dragEvent);
|
|
4681
|
+
this._onDragMove.fire(dragEvent);
|
|
4682
|
+
}
|
|
4683
|
+
_handleEnd(e, dropped) {
|
|
4684
|
+
var _a;
|
|
4685
|
+
const dragEvent = {
|
|
4686
|
+
clientX: e.clientX,
|
|
4687
|
+
clientY: e.clientY,
|
|
4688
|
+
pointerEvent: e,
|
|
4689
|
+
};
|
|
4690
|
+
if (dropped && this._currentTarget) {
|
|
4691
|
+
this._currentTarget.handleDrop(dragEvent);
|
|
4692
|
+
}
|
|
4693
|
+
else {
|
|
4694
|
+
(_a = this._currentTarget) === null || _a === void 0 ? void 0 : _a.handleDragLeave();
|
|
4695
|
+
}
|
|
4696
|
+
const onEnd = this._onDragEndCallback;
|
|
4697
|
+
const dataDisposable = this._dataDisposable;
|
|
4698
|
+
this._teardown();
|
|
4699
|
+
this._dataDisposable = undefined;
|
|
4700
|
+
// Defer disposal so drop handlers can still read the transfer data.
|
|
4701
|
+
setTimeout(() => dataDisposable === null || dataDisposable === void 0 ? void 0 : dataDisposable.dispose(), 0);
|
|
4702
|
+
onEnd === null || onEnd === void 0 ? void 0 : onEnd(dragEvent, dropped);
|
|
4703
|
+
this._onDragEnd.fire(dragEvent);
|
|
4704
|
+
}
|
|
4705
|
+
_teardown() {
|
|
4706
|
+
var _a, _b, _c, _d, _e;
|
|
4707
|
+
this._currentTarget = undefined;
|
|
4708
|
+
this._active = undefined;
|
|
4709
|
+
this._onDragMoveCallback = undefined;
|
|
4710
|
+
this._onDragEndCallback = undefined;
|
|
4711
|
+
(_a = this._ghost) === null || _a === void 0 ? void 0 : _a.dispose();
|
|
4712
|
+
this._ghost = undefined;
|
|
4713
|
+
(_b = this._iframeShield) === null || _b === void 0 ? void 0 : _b.release();
|
|
4714
|
+
this._iframeShield = undefined;
|
|
4715
|
+
(_c = this._moveListener) === null || _c === void 0 ? void 0 : _c.dispose();
|
|
4716
|
+
(_d = this._upListener) === null || _d === void 0 ? void 0 : _d.dispose();
|
|
4717
|
+
(_e = this._cancelListener) === null || _e === void 0 ? void 0 : _e.dispose();
|
|
4718
|
+
this._moveListener = undefined;
|
|
4719
|
+
this._upListener = undefined;
|
|
4720
|
+
this._cancelListener = undefined;
|
|
4674
4721
|
}
|
|
4675
4722
|
}
|
|
4676
4723
|
|
|
4677
|
-
|
|
4678
|
-
|
|
4679
|
-
|
|
4680
|
-
|
|
4681
|
-
|
|
4682
|
-
|
|
4683
|
-
|
|
4684
|
-
this.
|
|
4685
|
-
|
|
4686
|
-
|
|
4687
|
-
this.
|
|
4688
|
-
|
|
4689
|
-
|
|
4690
|
-
|
|
4691
|
-
|
|
4724
|
+
const DEFAULT_ACTIVATION_SIZE = {
|
|
4725
|
+
value: 20,
|
|
4726
|
+
type: 'percentage',
|
|
4727
|
+
};
|
|
4728
|
+
/** Pointer-driven counterpart to `Droptarget` with identical visual output. */
|
|
4729
|
+
class PointerDropTarget extends CompositeDisposable {
|
|
4730
|
+
get disabled() {
|
|
4731
|
+
return this._disabled;
|
|
4732
|
+
}
|
|
4733
|
+
set disabled(value) {
|
|
4734
|
+
this._disabled = value;
|
|
4735
|
+
if (value) {
|
|
4736
|
+
this._removeOverlay();
|
|
4737
|
+
}
|
|
4738
|
+
}
|
|
4739
|
+
get state() {
|
|
4740
|
+
return this._state;
|
|
4741
|
+
}
|
|
4742
|
+
constructor(element, options) {
|
|
4743
|
+
super();
|
|
4744
|
+
this.element = element;
|
|
4745
|
+
this.options = options;
|
|
4746
|
+
this._onDrop = new Emitter();
|
|
4747
|
+
this.onDrop = this._onDrop.event;
|
|
4748
|
+
this._onWillShowOverlay = new Emitter();
|
|
4749
|
+
this.onWillShowOverlay = this._onWillShowOverlay.event;
|
|
4750
|
+
this._disabled = false;
|
|
4751
|
+
this._acceptedTargetZonesSet = new Set(options.acceptedTargetZones);
|
|
4752
|
+
const handle = {
|
|
4753
|
+
element: this.element,
|
|
4754
|
+
handleDragOver: (e) => this._onDragOver(e),
|
|
4755
|
+
handleDragLeave: () => this._onDragLeave(),
|
|
4756
|
+
handleDrop: (e) => this._onDropEvent(e),
|
|
4757
|
+
};
|
|
4758
|
+
this.addDisposables(this._onDrop, this._onWillShowOverlay, PointerDragController.getInstance().registerTarget(handle));
|
|
4759
|
+
}
|
|
4760
|
+
setTargetZones(zones) {
|
|
4761
|
+
this._acceptedTargetZonesSet = new Set(zones);
|
|
4762
|
+
}
|
|
4763
|
+
setOverlayModel(model) {
|
|
4764
|
+
this.options.overlayModel = model;
|
|
4765
|
+
}
|
|
4766
|
+
dispose() {
|
|
4767
|
+
this._removeOverlay();
|
|
4768
|
+
super.dispose();
|
|
4769
|
+
}
|
|
4770
|
+
_onDragOver(event) {
|
|
4771
|
+
var _a, _b, _c, _d, _e;
|
|
4772
|
+
if (this._disabled) {
|
|
4773
|
+
this._removeOverlay();
|
|
4774
|
+
return;
|
|
4775
|
+
}
|
|
4776
|
+
const overrideTarget = (_b = (_a = this.options).getOverrideTarget) === null || _b === void 0 ? void 0 : _b.call(_a);
|
|
4777
|
+
if (this._acceptedTargetZonesSet.size === 0) {
|
|
4778
|
+
if (overrideTarget) {
|
|
4779
|
+
return;
|
|
4780
|
+
}
|
|
4781
|
+
this._removeOverlay();
|
|
4782
|
+
return;
|
|
4783
|
+
}
|
|
4784
|
+
const outlineEl = (_e = (_d = (_c = this.options).getOverlayOutline) === null || _d === void 0 ? void 0 : _d.call(_c)) !== null && _e !== void 0 ? _e : this.element;
|
|
4785
|
+
const width = outlineEl.offsetWidth;
|
|
4786
|
+
const height = outlineEl.offsetHeight;
|
|
4787
|
+
if (width === 0 || height === 0) {
|
|
4788
|
+
return;
|
|
4789
|
+
}
|
|
4790
|
+
const rect = outlineEl.getBoundingClientRect();
|
|
4791
|
+
const x = event.clientX - rect.left;
|
|
4792
|
+
const y = event.clientY - rect.top;
|
|
4793
|
+
const quadrant = this._calculateQuadrant(x, y, width, height);
|
|
4794
|
+
if (quadrant === null) {
|
|
4795
|
+
this._removeOverlay();
|
|
4796
|
+
return;
|
|
4797
|
+
}
|
|
4798
|
+
if (!this.options.canDisplayOverlay(event.pointerEvent, quadrant)) {
|
|
4799
|
+
if (overrideTarget) {
|
|
4800
|
+
return;
|
|
4801
|
+
}
|
|
4802
|
+
this._removeOverlay();
|
|
4803
|
+
return;
|
|
4804
|
+
}
|
|
4805
|
+
const willShow = new WillShowOverlayEvent({
|
|
4806
|
+
nativeEvent: event.pointerEvent,
|
|
4807
|
+
position: quadrant,
|
|
4808
|
+
});
|
|
4809
|
+
this._onWillShowOverlay.fire(willShow);
|
|
4810
|
+
if (willShow.defaultPrevented) {
|
|
4811
|
+
this._removeOverlay();
|
|
4812
|
+
return;
|
|
4813
|
+
}
|
|
4814
|
+
if (overrideTarget) {
|
|
4815
|
+
renderAnchoredOverlay({
|
|
4816
|
+
outlineElement: outlineEl,
|
|
4817
|
+
targetModel: overrideTarget,
|
|
4818
|
+
quadrant,
|
|
4819
|
+
width,
|
|
4820
|
+
height,
|
|
4821
|
+
overlayModel: this.options.overlayModel,
|
|
4822
|
+
className: this.options.className,
|
|
4823
|
+
});
|
|
4824
|
+
this._state = quadrant;
|
|
4825
|
+
return;
|
|
4826
|
+
}
|
|
4827
|
+
if (!this._targetElement) {
|
|
4828
|
+
const els = createOverlayElements();
|
|
4829
|
+
this._targetElement = els.dropzone;
|
|
4830
|
+
this._overlayElement = els.selection;
|
|
4831
|
+
this._state = 'center';
|
|
4832
|
+
this.element.classList.add('dv-drop-target');
|
|
4833
|
+
this.element.append(this._targetElement);
|
|
4834
|
+
}
|
|
4835
|
+
if (this._overlayElement) {
|
|
4836
|
+
renderInPlaceOverlay(this._overlayElement, quadrant, width, height, this.options.overlayModel);
|
|
4837
|
+
}
|
|
4838
|
+
this._state = quadrant;
|
|
4839
|
+
}
|
|
4840
|
+
_onDragLeave() {
|
|
4841
|
+
var _a, _b;
|
|
4842
|
+
const overrideTarget = (_b = (_a = this.options).getOverrideTarget) === null || _b === void 0 ? void 0 : _b.call(_a);
|
|
4843
|
+
// Anchor target owns its own lifecycle; just clear our latched
|
|
4844
|
+
// state so a subsequent pointerup doesn't fire a stale drop.
|
|
4845
|
+
if (overrideTarget) {
|
|
4846
|
+
this._state = undefined;
|
|
4847
|
+
overrideTarget.clear();
|
|
4848
|
+
return;
|
|
4849
|
+
}
|
|
4850
|
+
this._removeOverlay();
|
|
4851
|
+
}
|
|
4852
|
+
_onDropEvent(event) {
|
|
4853
|
+
var _a, _b;
|
|
4854
|
+
const state = this._state;
|
|
4855
|
+
const overrideTarget = (_b = (_a = this.options).getOverrideTarget) === null || _b === void 0 ? void 0 : _b.call(_a);
|
|
4856
|
+
this._removeOverlay();
|
|
4857
|
+
overrideTarget === null || overrideTarget === void 0 ? void 0 : overrideTarget.clear();
|
|
4858
|
+
if (state) {
|
|
4859
|
+
this._onDrop.fire({
|
|
4860
|
+
position: state,
|
|
4861
|
+
nativeEvent: event.pointerEvent,
|
|
4862
|
+
});
|
|
4863
|
+
}
|
|
4864
|
+
}
|
|
4865
|
+
_calculateQuadrant(x, y, width, height) {
|
|
4866
|
+
var _a, _b;
|
|
4867
|
+
const activation = (_b = (_a = this.options.overlayModel) === null || _a === void 0 ? void 0 : _a.activationSize) !== null && _b !== void 0 ? _b : DEFAULT_ACTIVATION_SIZE;
|
|
4868
|
+
if (activation.type === 'percentage') {
|
|
4869
|
+
return calculateQuadrantAsPercentage(this._acceptedTargetZonesSet, x, y, width, height, activation.value);
|
|
4870
|
+
}
|
|
4871
|
+
return calculateQuadrantAsPixels(this._acceptedTargetZonesSet, x, y, width, height, activation.value);
|
|
4872
|
+
}
|
|
4873
|
+
_removeOverlay() {
|
|
4874
|
+
var _a;
|
|
4875
|
+
if (this._targetElement) {
|
|
4876
|
+
this._state = undefined;
|
|
4877
|
+
(_a = this._targetElement.parentElement) === null || _a === void 0 ? void 0 : _a.classList.remove('dv-drop-target');
|
|
4878
|
+
this._targetElement.remove();
|
|
4879
|
+
this._targetElement = undefined;
|
|
4880
|
+
this._overlayElement = undefined;
|
|
4881
|
+
}
|
|
4882
|
+
else {
|
|
4883
|
+
this._state = undefined;
|
|
4884
|
+
}
|
|
4885
|
+
}
|
|
4886
|
+
}
|
|
4887
|
+
|
|
4888
|
+
const DEFAULT_THRESHOLD = 5;
|
|
4889
|
+
const DEFAULT_TOUCH_INITIATION_DELAY = 250;
|
|
4890
|
+
const DEFAULT_PRESS_TOLERANCE = 8;
|
|
4891
|
+
/**
|
|
4892
|
+
* Pointer-event drag source. Waits for movement past `threshold` (and
|
|
4893
|
+
* touch-only `touchInitiationDelay`) before promoting to a drag so taps
|
|
4894
|
+
* pass through unaffected.
|
|
4895
|
+
*/
|
|
4896
|
+
class PointerDragSource extends CompositeDisposable {
|
|
4897
|
+
constructor(element, options) {
|
|
4898
|
+
var _a;
|
|
4899
|
+
super();
|
|
4900
|
+
this.element = element;
|
|
4901
|
+
this.options = options;
|
|
4902
|
+
this._disabled = false;
|
|
4903
|
+
this._armed = false;
|
|
4904
|
+
this._startX = 0;
|
|
4905
|
+
this._startY = 0;
|
|
4906
|
+
this._touchOnly = (_a = options.touchOnly) !== null && _a !== void 0 ? _a : true;
|
|
4907
|
+
this.addDisposables(addDisposableListener(this.element, 'pointerdown', (e) => {
|
|
4908
|
+
this._onPointerDown(e);
|
|
4909
|
+
}));
|
|
4910
|
+
}
|
|
4911
|
+
setDisabled(value) {
|
|
4912
|
+
this._disabled = value;
|
|
4913
|
+
if (value) {
|
|
4914
|
+
this._cancelPending();
|
|
4915
|
+
}
|
|
4916
|
+
}
|
|
4917
|
+
/**
|
|
4918
|
+
* `false` lets the pointer source also handle mouse pointers; used when
|
|
4919
|
+
* `dndStrategy: 'pointer'` to drive every input type through this path.
|
|
4920
|
+
*/
|
|
4921
|
+
setTouchOnly(value) {
|
|
4922
|
+
if (this._touchOnly === value) {
|
|
4923
|
+
return;
|
|
4924
|
+
}
|
|
4925
|
+
this._touchOnly = value;
|
|
4926
|
+
// A pending mouse-tracked drag should be abandoned if we re-enable
|
|
4927
|
+
// the touch-only filter mid-flight.
|
|
4928
|
+
if (value) {
|
|
4929
|
+
this._cancelPending();
|
|
4930
|
+
}
|
|
4931
|
+
}
|
|
4932
|
+
_shouldHandle(event) {
|
|
4933
|
+
var _a, _b;
|
|
4934
|
+
if (this._disabled) {
|
|
4935
|
+
return false;
|
|
4936
|
+
}
|
|
4937
|
+
// Pointer-type filter runs before isCancelled — consumer state read
|
|
4938
|
+
// by isCancelled may not be populated for events we'll never handle.
|
|
4939
|
+
if (this._touchOnly &&
|
|
4940
|
+
event.pointerType !== 'touch' &&
|
|
4941
|
+
event.pointerType !== 'pen') {
|
|
4942
|
+
return false;
|
|
4943
|
+
}
|
|
4944
|
+
if ((_b = (_a = this.options).isCancelled) === null || _b === void 0 ? void 0 : _b.call(_a, event)) {
|
|
4945
|
+
return false;
|
|
4946
|
+
}
|
|
4947
|
+
return true;
|
|
4948
|
+
}
|
|
4949
|
+
_onPointerDown(event) {
|
|
4950
|
+
var _a, _b, _c, _d, _e;
|
|
4951
|
+
if (!this._shouldHandle(event)) {
|
|
4952
|
+
return;
|
|
4953
|
+
}
|
|
4954
|
+
// Defensive: a fresh pointerdown supersedes any in-flight tracking.
|
|
4955
|
+
this._cancelPending();
|
|
4956
|
+
this._pendingPointerId = event.pointerId;
|
|
4957
|
+
this._startX = event.clientX;
|
|
4958
|
+
this._startY = event.clientY;
|
|
4959
|
+
this._startEvent = event;
|
|
4960
|
+
const isTouch = event.pointerType === 'touch' || event.pointerType === 'pen';
|
|
4961
|
+
// Touch waits a short window so a still finger can press-and-hold
|
|
4962
|
+
// before drifting; once the timer fires, any motion past `threshold`
|
|
4963
|
+
// begins the drag.
|
|
4964
|
+
const initiationDelayOpt = this.options.touchInitiationDelay;
|
|
4965
|
+
const initiationDelay = (_a = (typeof initiationDelayOpt === 'function'
|
|
4966
|
+
? initiationDelayOpt()
|
|
4967
|
+
: initiationDelayOpt)) !== null && _a !== void 0 ? _a : DEFAULT_TOUCH_INITIATION_DELAY;
|
|
4968
|
+
this._armed = !isTouch || initiationDelay <= 0;
|
|
4969
|
+
if (isTouch && initiationDelay > 0 && isFinite(initiationDelay)) {
|
|
4970
|
+
this._armTimer = setTimeout(() => {
|
|
4971
|
+
this._armTimer = undefined;
|
|
4972
|
+
this._armed = true;
|
|
4973
|
+
}, initiationDelay);
|
|
4974
|
+
}
|
|
4975
|
+
const threshold = (_b = this.options.threshold) !== null && _b !== void 0 ? _b : DEFAULT_THRESHOLD;
|
|
4976
|
+
const pressToleranceOpt = this.options.pressTolerance;
|
|
4977
|
+
const pressTolerance = (_c = (typeof pressToleranceOpt === 'function'
|
|
4978
|
+
? pressToleranceOpt()
|
|
4979
|
+
: pressToleranceOpt)) !== null && _c !== void 0 ? _c : DEFAULT_PRESS_TOLERANCE;
|
|
4980
|
+
// Source's owning window — popout drags fire on their own window.
|
|
4981
|
+
const targetWindow = (_e = (_d = this.element.ownerDocument) === null || _d === void 0 ? void 0 : _d.defaultView) !== null && _e !== void 0 ? _e : window;
|
|
4982
|
+
this._pendingMoveListener = addDisposableListener(targetWindow, 'pointermove', (moveEvent) => {
|
|
4983
|
+
if (moveEvent.pointerId !== this._pendingPointerId) {
|
|
4984
|
+
return;
|
|
4985
|
+
}
|
|
4986
|
+
const dx = moveEvent.clientX - this._startX;
|
|
4987
|
+
const dy = moveEvent.clientY - this._startY;
|
|
4988
|
+
const distance = Math.hypot(dx, dy);
|
|
4989
|
+
if (this._armed) {
|
|
4990
|
+
if (distance >= threshold) {
|
|
4991
|
+
this._beginDrag(moveEvent);
|
|
4992
|
+
}
|
|
4993
|
+
return;
|
|
4994
|
+
}
|
|
4995
|
+
// Pre-arm phase: a flick past `pressTolerance` in any
|
|
4996
|
+
// direction is treated as drag intent. The element opts out
|
|
4997
|
+
// of native scroll via `touch-action: none`; container-level
|
|
4998
|
+
// scrolling lives on the surrounding strip's empty space.
|
|
4999
|
+
if (distance > pressTolerance) {
|
|
5000
|
+
this._beginDrag(moveEvent);
|
|
5001
|
+
}
|
|
5002
|
+
});
|
|
5003
|
+
this._pendingUpListener = addDisposableListener(targetWindow, 'pointerup', (upEvent) => {
|
|
5004
|
+
if (upEvent.pointerId !== this._pendingPointerId) {
|
|
5005
|
+
return;
|
|
5006
|
+
}
|
|
5007
|
+
this._cancelPending();
|
|
5008
|
+
});
|
|
5009
|
+
this._pendingCancelListener = addDisposableListener(targetWindow, 'pointercancel', (cancelEvent) => {
|
|
5010
|
+
if (cancelEvent.pointerId !== this._pendingPointerId) {
|
|
5011
|
+
return;
|
|
5012
|
+
}
|
|
5013
|
+
this._cancelPending();
|
|
5014
|
+
});
|
|
5015
|
+
}
|
|
5016
|
+
/** For sibling gesture detectors (e.g. LongPressDetector) to dismiss a pending drag. */
|
|
5017
|
+
cancelPending() {
|
|
5018
|
+
this._cancelPending();
|
|
5019
|
+
}
|
|
5020
|
+
_cancelPending() {
|
|
5021
|
+
var _a, _b, _c;
|
|
5022
|
+
this._pendingPointerId = undefined;
|
|
5023
|
+
if (this._armTimer !== undefined) {
|
|
5024
|
+
clearTimeout(this._armTimer);
|
|
5025
|
+
this._armTimer = undefined;
|
|
5026
|
+
}
|
|
5027
|
+
this._armed = false;
|
|
5028
|
+
(_a = this._pendingMoveListener) === null || _a === void 0 ? void 0 : _a.dispose();
|
|
5029
|
+
(_b = this._pendingUpListener) === null || _b === void 0 ? void 0 : _b.dispose();
|
|
5030
|
+
(_c = this._pendingCancelListener) === null || _c === void 0 ? void 0 : _c.dispose();
|
|
5031
|
+
this._pendingMoveListener = undefined;
|
|
5032
|
+
this._pendingUpListener = undefined;
|
|
5033
|
+
this._pendingCancelListener = undefined;
|
|
5034
|
+
this._startEvent = undefined;
|
|
5035
|
+
}
|
|
5036
|
+
_beginDrag(triggerEvent) {
|
|
5037
|
+
var _a, _b, _c, _d, _e;
|
|
5038
|
+
const startEvent = (_a = this._startEvent) !== null && _a !== void 0 ? _a : triggerEvent;
|
|
5039
|
+
this._cancelPending();
|
|
5040
|
+
(_c = (_b = this.options).onDragStart) === null || _c === void 0 ? void 0 : _c.call(_b, startEvent);
|
|
5041
|
+
const ghost = (_e = (_d = this.options).createGhost) === null || _e === void 0 ? void 0 : _e.call(_d, startEvent);
|
|
5042
|
+
PointerDragController.getInstance().beginDrag({
|
|
5043
|
+
pointerEvent: triggerEvent,
|
|
5044
|
+
source: this.element,
|
|
5045
|
+
getData: () => this.options.getData(startEvent),
|
|
5046
|
+
ghost,
|
|
5047
|
+
onDragMove: this.options.onDragMove,
|
|
5048
|
+
onDragEnd: this.options.onDragEnd,
|
|
5049
|
+
});
|
|
5050
|
+
}
|
|
5051
|
+
dispose() {
|
|
5052
|
+
this._cancelPending();
|
|
5053
|
+
super.dispose();
|
|
5054
|
+
}
|
|
5055
|
+
}
|
|
5056
|
+
|
|
5057
|
+
/**
|
|
5058
|
+
* Floating clone that follows the pointer; appended to the owning
|
|
5059
|
+
* document's body with `pointer-events: none` so it doesn't intercept
|
|
5060
|
+
* hit-testing.
|
|
5061
|
+
*/
|
|
5062
|
+
class PointerGhost {
|
|
5063
|
+
constructor(opts) {
|
|
5064
|
+
var _a, _b, _c, _d, _e;
|
|
5065
|
+
this._disposed = false;
|
|
5066
|
+
this.element = opts.element;
|
|
5067
|
+
this.offsetX = (_a = opts.offsetX) !== null && _a !== void 0 ? _a : 0;
|
|
5068
|
+
this.offsetY = (_b = opts.offsetY) !== null && _b !== void 0 ? _b : 0;
|
|
5069
|
+
// Animate via transform (see update); position:fixed for scroll-independence.
|
|
5070
|
+
this.element.style.position = 'fixed';
|
|
5071
|
+
this.element.style.left = '0px';
|
|
5072
|
+
this.element.style.top = '0px';
|
|
5073
|
+
this.element.style.pointerEvents = 'none';
|
|
5074
|
+
this.element.style.zIndex = '99999';
|
|
5075
|
+
this.element.style.opacity = String((_c = opts.opacity) !== null && _c !== void 0 ? _c : 0.8);
|
|
5076
|
+
this.element.style.willChange = 'transform';
|
|
5077
|
+
this.element.style.transform = `translate3d(${opts.initialX - this.offsetX}px, ${opts.initialY - this.offsetY}px, 0)`;
|
|
5078
|
+
const ownerDocument = (_e = (_d = opts.owner) === null || _d === void 0 ? void 0 : _d.ownerDocument) !== null && _e !== void 0 ? _e : document;
|
|
5079
|
+
ownerDocument.body.appendChild(this.element);
|
|
5080
|
+
}
|
|
5081
|
+
update(clientX, clientY) {
|
|
5082
|
+
if (this._disposed) {
|
|
5083
|
+
return;
|
|
5084
|
+
}
|
|
5085
|
+
// translate3d composites on the GPU — no layout per pointermove.
|
|
5086
|
+
this.element.style.transform = `translate3d(${clientX - this.offsetX}px, ${clientY - this.offsetY}px, 0)`;
|
|
5087
|
+
}
|
|
5088
|
+
dispose() {
|
|
5089
|
+
if (this._disposed) {
|
|
5090
|
+
return;
|
|
5091
|
+
}
|
|
5092
|
+
this._disposed = true;
|
|
5093
|
+
this.element.remove();
|
|
5094
|
+
}
|
|
5095
|
+
}
|
|
5096
|
+
|
|
5097
|
+
/**
|
|
5098
|
+
* HTML5 drag source. Listens for the native `dragstart` event, calls
|
|
5099
|
+
* `getData` to populate transfer, optionally renders the ghost via
|
|
5100
|
+
* `setDragImage`, fires `onDragStart` / `onDragEnd`, and tears down the
|
|
5101
|
+
* transfer disposer after `dragend`.
|
|
5102
|
+
*/
|
|
5103
|
+
class Html5DragSource extends CompositeDisposable {
|
|
5104
|
+
constructor(el, opts) {
|
|
5105
|
+
super();
|
|
5106
|
+
this.el = el;
|
|
5107
|
+
this.opts = opts;
|
|
5108
|
+
this._dataDisposable = new MutableDisposable();
|
|
5109
|
+
this._pointerEventsDisposable = new MutableDisposable();
|
|
5110
|
+
this._disabled = !!opts.disabled;
|
|
5111
|
+
this.addDisposables(this._dataDisposable, this._pointerEventsDisposable, addDisposableListener(this.el, 'dragstart', (event) => {
|
|
5112
|
+
var _a, _b, _c, _d, _e, _f, _g, _h, _j;
|
|
5113
|
+
if (event.defaultPrevented ||
|
|
5114
|
+
this._disabled ||
|
|
5115
|
+
((_b = (_a = this.opts).isCancelled) === null || _b === void 0 ? void 0 : _b.call(_a, event))) {
|
|
5116
|
+
event.preventDefault();
|
|
5117
|
+
return;
|
|
5118
|
+
}
|
|
5119
|
+
// Iframes capture pointermove once the cursor enters them,
|
|
5120
|
+
// which freezes drag tracking from the parent window's
|
|
5121
|
+
// POV. Shield the source's owning document so popout-window
|
|
5122
|
+
// drags shield the popout, not the main window.
|
|
5123
|
+
const iframes = disableIframePointEvents((_c = this.el.ownerDocument) !== null && _c !== void 0 ? _c : document);
|
|
5124
|
+
this._pointerEventsDisposable.value = {
|
|
5125
|
+
dispose: () => iframes.release(),
|
|
5126
|
+
};
|
|
5127
|
+
this.el.classList.add('dv-dragged');
|
|
5128
|
+
setTimeout(() => this.el.classList.remove('dv-dragged'), 0);
|
|
5129
|
+
this._dataDisposable.value = this.opts.getData(event);
|
|
5130
|
+
const ghost = (_e = (_d = this.opts).createGhost) === null || _e === void 0 ? void 0 : _e.call(_d, event);
|
|
5131
|
+
if (ghost && event.dataTransfer) {
|
|
5132
|
+
addGhostImage(event.dataTransfer, ghost.element, {
|
|
5133
|
+
x: (_f = ghost.offsetX) !== null && _f !== void 0 ? _f : 0,
|
|
5134
|
+
y: (_g = ghost.offsetY) !== null && _g !== void 0 ? _g : 0,
|
|
5135
|
+
});
|
|
5136
|
+
if (ghost.dispose) {
|
|
5137
|
+
// addGhostImage removes the element from the DOM on
|
|
5138
|
+
// the next tick; dispose the framework renderer on
|
|
5139
|
+
// the same schedule.
|
|
5140
|
+
const disposeGhost = ghost.dispose;
|
|
5141
|
+
setTimeout(() => disposeGhost(), 0);
|
|
5142
|
+
}
|
|
5143
|
+
}
|
|
5144
|
+
if (event.dataTransfer) {
|
|
5145
|
+
event.dataTransfer.effectAllowed = 'move';
|
|
5146
|
+
// Some third-party DnD libs (e.g. react-dnd) cancel the
|
|
5147
|
+
// dragstart when `dataTransfer.types` is empty.
|
|
5148
|
+
if (event.dataTransfer.items.length === 0) {
|
|
5149
|
+
event.dataTransfer.setData('text/plain', '');
|
|
5150
|
+
}
|
|
5151
|
+
}
|
|
5152
|
+
(_j = (_h = this.opts).onDragStart) === null || _j === void 0 ? void 0 : _j.call(_h, event);
|
|
5153
|
+
}), addDisposableListener(this.el, 'dragend', (event) => {
|
|
5154
|
+
var _a, _b;
|
|
5155
|
+
this._pointerEventsDisposable.dispose();
|
|
5156
|
+
// Defer disposal so drop handlers can still read the
|
|
5157
|
+
// transfer payload before it clears.
|
|
5158
|
+
setTimeout(() => this._dataDisposable.dispose(), 0);
|
|
5159
|
+
(_b = (_a = this.opts).onDragEnd) === null || _b === void 0 ? void 0 : _b.call(_a, event);
|
|
5160
|
+
}));
|
|
5161
|
+
}
|
|
5162
|
+
setDisabled(value) {
|
|
5163
|
+
this._disabled = value;
|
|
5164
|
+
}
|
|
5165
|
+
setTouchOnly(_) {
|
|
5166
|
+
// No-op — HTML5 path can't filter by pointer type.
|
|
5167
|
+
}
|
|
5168
|
+
cancelPending() {
|
|
5169
|
+
// No-op — HTML5 has no pre-arm phase to cancel.
|
|
5170
|
+
}
|
|
5171
|
+
}
|
|
5172
|
+
class Html5DragBackend {
|
|
5173
|
+
constructor() {
|
|
5174
|
+
this.kind = 'html5';
|
|
5175
|
+
}
|
|
5176
|
+
createDropTarget(element, options) {
|
|
5177
|
+
return new Droptarget(element, options);
|
|
5178
|
+
}
|
|
5179
|
+
createDragSource(element, options) {
|
|
5180
|
+
return new Html5DragSource(element, options);
|
|
5181
|
+
}
|
|
5182
|
+
}
|
|
5183
|
+
class PointerDragBackend {
|
|
5184
|
+
constructor() {
|
|
5185
|
+
this.kind = 'pointer';
|
|
5186
|
+
}
|
|
5187
|
+
createDropTarget(element, options) {
|
|
5188
|
+
return new PointerDropTarget(element, options);
|
|
5189
|
+
}
|
|
5190
|
+
createDragSource(element, options) {
|
|
5191
|
+
const pointerCreateGhost = options.createGhost
|
|
5192
|
+
? (event) => {
|
|
5193
|
+
const spec = options.createGhost(event);
|
|
5194
|
+
if (!spec) {
|
|
5195
|
+
return undefined;
|
|
5196
|
+
}
|
|
5197
|
+
const ghost = new PointerGhost({
|
|
5198
|
+
element: spec.element,
|
|
5199
|
+
initialX: event.clientX,
|
|
5200
|
+
initialY: event.clientY,
|
|
5201
|
+
offsetX: spec.offsetX,
|
|
5202
|
+
offsetY: spec.offsetY,
|
|
5203
|
+
owner: element,
|
|
5204
|
+
});
|
|
5205
|
+
if (spec.dispose) {
|
|
5206
|
+
const baseDispose = ghost.dispose.bind(ghost);
|
|
5207
|
+
const disposeSpec = spec.dispose;
|
|
5208
|
+
ghost.dispose = () => {
|
|
5209
|
+
baseDispose();
|
|
5210
|
+
disposeSpec();
|
|
5211
|
+
};
|
|
5212
|
+
}
|
|
5213
|
+
return ghost;
|
|
5214
|
+
}
|
|
5215
|
+
: undefined;
|
|
5216
|
+
const source = new PointerDragSource(element, {
|
|
5217
|
+
getData: options.getData,
|
|
5218
|
+
isCancelled: options.isCancelled,
|
|
5219
|
+
onDragStart: options.onDragStart,
|
|
5220
|
+
onDragEnd: options.onDragEnd
|
|
5221
|
+
? (event) => options.onDragEnd(event.pointerEvent)
|
|
5222
|
+
: undefined,
|
|
5223
|
+
createGhost: pointerCreateGhost,
|
|
5224
|
+
touchOnly: options.touchOnly,
|
|
5225
|
+
touchInitiationDelay: options.touchInitiationDelay,
|
|
5226
|
+
pressTolerance: options.pressTolerance,
|
|
5227
|
+
threshold: options.threshold,
|
|
5228
|
+
});
|
|
5229
|
+
if (options.disabled) {
|
|
5230
|
+
source.setDisabled(true);
|
|
5231
|
+
}
|
|
5232
|
+
return source;
|
|
5233
|
+
}
|
|
5234
|
+
}
|
|
5235
|
+
const html5Backend = new Html5DragBackend();
|
|
5236
|
+
const pointerBackend = new PointerDragBackend();
|
|
5237
|
+
|
|
5238
|
+
const PROPERTY_KEYS_PANEVIEW = (() => {
|
|
5239
|
+
/**
|
|
5240
|
+
* by readong the keys from an empty value object TypeScript will error
|
|
5241
|
+
* when we add or remove new properties to `DockviewOptions`
|
|
5242
|
+
*/
|
|
5243
|
+
const properties = {
|
|
5244
|
+
disableAutoResizing: undefined,
|
|
5245
|
+
disableDnd: undefined,
|
|
5246
|
+
className: undefined,
|
|
5247
|
+
};
|
|
5248
|
+
return Object.keys(properties);
|
|
5249
|
+
})();
|
|
5250
|
+
class PaneviewUnhandledDragOverEvent extends AcceptableEvent {
|
|
5251
|
+
constructor(nativeEvent, position, getData, panel) {
|
|
5252
|
+
super();
|
|
5253
|
+
this.nativeEvent = nativeEvent;
|
|
5254
|
+
this.position = position;
|
|
5255
|
+
this.getData = getData;
|
|
5256
|
+
this.panel = panel;
|
|
5257
|
+
}
|
|
5258
|
+
}
|
|
5259
|
+
|
|
5260
|
+
class WillFocusEvent extends DockviewEvent {
|
|
5261
|
+
constructor() {
|
|
5262
|
+
super();
|
|
5263
|
+
}
|
|
5264
|
+
}
|
|
5265
|
+
/**
|
|
5266
|
+
* A core api implementation that should be used across all panel-like objects
|
|
5267
|
+
*/
|
|
5268
|
+
class PanelApiImpl extends CompositeDisposable {
|
|
5269
|
+
get isFocused() {
|
|
5270
|
+
return this._isFocused;
|
|
5271
|
+
}
|
|
5272
|
+
get isActive() {
|
|
5273
|
+
return this._isActive;
|
|
5274
|
+
}
|
|
5275
|
+
get isVisible() {
|
|
5276
|
+
return this._isVisible;
|
|
5277
|
+
}
|
|
5278
|
+
get width() {
|
|
5279
|
+
return this._width;
|
|
5280
|
+
}
|
|
5281
|
+
get height() {
|
|
5282
|
+
return this._height;
|
|
5283
|
+
}
|
|
5284
|
+
constructor(id, component) {
|
|
5285
|
+
super();
|
|
5286
|
+
this.id = id;
|
|
5287
|
+
this.component = component;
|
|
5288
|
+
this._isFocused = false;
|
|
5289
|
+
this._isActive = false;
|
|
5290
|
+
this._isVisible = true;
|
|
5291
|
+
this._width = 0;
|
|
5292
|
+
this._height = 0;
|
|
5293
|
+
this._parameters = {};
|
|
5294
|
+
this.panelUpdatesDisposable = new MutableDisposable();
|
|
5295
|
+
this._onDidDimensionChange = new Emitter();
|
|
5296
|
+
this.onDidDimensionsChange = this._onDidDimensionChange.event;
|
|
5297
|
+
this._onDidChangeFocus = new Emitter();
|
|
5298
|
+
this.onDidFocusChange = this._onDidChangeFocus.event;
|
|
5299
|
+
//
|
|
5300
|
+
this._onWillFocus = new Emitter();
|
|
5301
|
+
this.onWillFocus = this._onWillFocus.event;
|
|
5302
|
+
//
|
|
5303
|
+
this._onDidVisibilityChange = new Emitter();
|
|
5304
|
+
this.onDidVisibilityChange = this._onDidVisibilityChange.event;
|
|
5305
|
+
this._onWillVisibilityChange = new Emitter();
|
|
5306
|
+
this.onWillVisibilityChange = this._onWillVisibilityChange.event;
|
|
5307
|
+
this._onDidActiveChange = new Emitter();
|
|
5308
|
+
this.onDidActiveChange = this._onDidActiveChange.event;
|
|
5309
|
+
this._onActiveChange = new Emitter();
|
|
5310
|
+
this.onActiveChange = this._onActiveChange.event;
|
|
5311
|
+
this._onDidParametersChange = new Emitter();
|
|
5312
|
+
this.onDidParametersChange = this._onDidParametersChange.event;
|
|
5313
|
+
this.addDisposables(this.onDidFocusChange((event) => {
|
|
5314
|
+
this._isFocused = event.isFocused;
|
|
5315
|
+
}), this.onDidActiveChange((event) => {
|
|
5316
|
+
this._isActive = event.isActive;
|
|
5317
|
+
}), this.onDidVisibilityChange((event) => {
|
|
5318
|
+
this._isVisible = event.isVisible;
|
|
5319
|
+
}), this.onDidDimensionsChange((event) => {
|
|
5320
|
+
this._width = event.width;
|
|
5321
|
+
this._height = event.height;
|
|
5322
|
+
}), this.panelUpdatesDisposable, this._onDidDimensionChange, this._onDidChangeFocus, this._onDidVisibilityChange, this._onDidActiveChange, this._onWillFocus, this._onActiveChange, this._onWillFocus, this._onWillVisibilityChange, this._onDidParametersChange);
|
|
5323
|
+
}
|
|
5324
|
+
getParameters() {
|
|
5325
|
+
return this._parameters;
|
|
5326
|
+
}
|
|
5327
|
+
initialize(panel) {
|
|
5328
|
+
this.panelUpdatesDisposable.value = this._onDidParametersChange.event((parameters) => {
|
|
5329
|
+
this._parameters = parameters;
|
|
5330
|
+
panel.update({
|
|
5331
|
+
params: parameters,
|
|
5332
|
+
});
|
|
5333
|
+
});
|
|
5334
|
+
}
|
|
5335
|
+
setVisible(isVisible) {
|
|
5336
|
+
this._onWillVisibilityChange.fire({ isVisible });
|
|
5337
|
+
}
|
|
5338
|
+
setActive() {
|
|
5339
|
+
this._onActiveChange.fire();
|
|
5340
|
+
}
|
|
5341
|
+
updateParameters(parameters) {
|
|
5342
|
+
this._onDidParametersChange.fire(parameters);
|
|
5343
|
+
}
|
|
5344
|
+
}
|
|
5345
|
+
|
|
5346
|
+
class SplitviewPanelApiImpl extends PanelApiImpl {
|
|
5347
|
+
//
|
|
5348
|
+
constructor(id, component) {
|
|
5349
|
+
super(id, component);
|
|
5350
|
+
this._onDidConstraintsChangeInternal = new Emitter();
|
|
5351
|
+
this.onDidConstraintsChangeInternal = this._onDidConstraintsChangeInternal.event;
|
|
5352
|
+
//
|
|
5353
|
+
this._onDidConstraintsChange = new Emitter({
|
|
5354
|
+
replay: true,
|
|
5355
|
+
});
|
|
5356
|
+
this.onDidConstraintsChange = this._onDidConstraintsChange.event;
|
|
5357
|
+
//
|
|
5358
|
+
this._onDidSizeChange = new Emitter();
|
|
5359
|
+
this.onDidSizeChange = this._onDidSizeChange.event;
|
|
5360
|
+
this.addDisposables(this._onDidConstraintsChangeInternal, this._onDidConstraintsChange, this._onDidSizeChange);
|
|
4692
5361
|
}
|
|
4693
5362
|
setConstraints(value) {
|
|
4694
5363
|
this._onDidConstraintsChangeInternal.fire(value);
|
|
@@ -5031,35 +5700,42 @@
|
|
|
5031
5700
|
const id = this.id;
|
|
5032
5701
|
const accessorId = this.accessor.id;
|
|
5033
5702
|
this.header.draggable = true;
|
|
5034
|
-
|
|
5035
|
-
getData() {
|
|
5703
|
+
const sharedDragOptions = {
|
|
5704
|
+
getData: () => {
|
|
5036
5705
|
LocalSelectionTransfer.getInstance().setData([new PaneTransfer(accessorId, id)], PaneTransfer.prototype);
|
|
5037
5706
|
return {
|
|
5038
5707
|
dispose: () => {
|
|
5039
5708
|
LocalSelectionTransfer.getInstance().clearData(PaneTransfer.prototype);
|
|
5040
5709
|
},
|
|
5041
5710
|
};
|
|
5711
|
+
},
|
|
5712
|
+
};
|
|
5713
|
+
this.html5DragSource = html5Backend.createDragSource(this.header, sharedDragOptions);
|
|
5714
|
+
this.pointerDragSource = pointerBackend.createDragSource(this.header, sharedDragOptions);
|
|
5715
|
+
const canDisplayOverlay = (event, position) => {
|
|
5716
|
+
const data = getPaneData();
|
|
5717
|
+
if (data) {
|
|
5718
|
+
if (data.paneId !== this.id &&
|
|
5719
|
+
data.viewId === this.accessor.id) {
|
|
5720
|
+
return true;
|
|
5721
|
+
}
|
|
5042
5722
|
}
|
|
5043
|
-
|
|
5044
|
-
|
|
5723
|
+
const firedEvent = new PaneviewUnhandledDragOverEvent(event, position, getPaneData, this);
|
|
5724
|
+
this._onUnhandledDragOverEvent.fire(firedEvent);
|
|
5725
|
+
return firedEvent.isAccepted;
|
|
5726
|
+
};
|
|
5727
|
+
const dropTargetOptions = {
|
|
5045
5728
|
acceptedTargetZones: ['top', 'bottom'],
|
|
5046
5729
|
overlayModel: {
|
|
5047
5730
|
activationSize: { type: 'percentage', value: 50 },
|
|
5048
5731
|
},
|
|
5049
|
-
canDisplayOverlay
|
|
5050
|
-
|
|
5051
|
-
|
|
5052
|
-
|
|
5053
|
-
|
|
5054
|
-
|
|
5055
|
-
|
|
5056
|
-
}
|
|
5057
|
-
const firedEvent = new PaneviewUnhandledDragOverEvent(event, position, getPaneData, this);
|
|
5058
|
-
this._onUnhandledDragOverEvent.fire(firedEvent);
|
|
5059
|
-
return firedEvent.isAccepted;
|
|
5060
|
-
},
|
|
5061
|
-
});
|
|
5062
|
-
this.addDisposables(this._onDidDrop, this.handler, this.target, this.target.onDrop((event) => {
|
|
5732
|
+
canDisplayOverlay,
|
|
5733
|
+
};
|
|
5734
|
+
this.target = html5Backend.createDropTarget(this.element, dropTargetOptions);
|
|
5735
|
+
this.pointerTarget = pointerBackend.createDropTarget(this.element, dropTargetOptions);
|
|
5736
|
+
this.addDisposables(this._onDidDrop, this.html5DragSource, this.pointerDragSource, this.target, this.pointerTarget, this.target.onDrop((event) => {
|
|
5737
|
+
this.onDrop(event);
|
|
5738
|
+
}), this.pointerTarget.onDrop((event) => {
|
|
5063
5739
|
this.onDrop(event);
|
|
5064
5740
|
}));
|
|
5065
5741
|
}
|
|
@@ -5114,6 +5790,25 @@
|
|
|
5114
5790
|
this._element.tabIndex = -1;
|
|
5115
5791
|
this.addDisposables(this._onDidFocus, this._onDidBlur);
|
|
5116
5792
|
const target = group.dropTargetContainer;
|
|
5793
|
+
const canDisplayOverlay = (event, position) => {
|
|
5794
|
+
if (this.group.locked === 'no-drop-target' ||
|
|
5795
|
+
(this.group.locked && position === 'center')) {
|
|
5796
|
+
return false;
|
|
5797
|
+
}
|
|
5798
|
+
const data = getPanelData();
|
|
5799
|
+
if (!data &&
|
|
5800
|
+
event.shiftKey &&
|
|
5801
|
+
this.group.location.type !== 'floating') {
|
|
5802
|
+
return false;
|
|
5803
|
+
}
|
|
5804
|
+
if (data && data.viewId === this.accessor.id) {
|
|
5805
|
+
return true;
|
|
5806
|
+
}
|
|
5807
|
+
return this.group.canDisplayOverlay(event, position, 'content');
|
|
5808
|
+
};
|
|
5809
|
+
// `dropTarget` stays the concrete `Droptarget` (not via the backend
|
|
5810
|
+
// factory) because overlayRenderContainer forwards HTML5 drag events
|
|
5811
|
+
// through `dropTarget.dnd` — that field is not part of `IDropTarget`.
|
|
5117
5812
|
this.dropTarget = new Droptarget(this.element, {
|
|
5118
5813
|
getOverlayOutline: () => {
|
|
5119
5814
|
var _a;
|
|
@@ -5123,25 +5818,22 @@
|
|
|
5123
5818
|
},
|
|
5124
5819
|
className: 'dv-drop-target-content',
|
|
5125
5820
|
acceptedTargetZones: ['top', 'bottom', 'left', 'right', 'center'],
|
|
5126
|
-
canDisplayOverlay
|
|
5127
|
-
|
|
5128
|
-
|
|
5129
|
-
|
|
5130
|
-
|
|
5131
|
-
|
|
5132
|
-
|
|
5133
|
-
|
|
5134
|
-
|
|
5135
|
-
|
|
5136
|
-
|
|
5137
|
-
if (data && data.viewId === this.accessor.id) {
|
|
5138
|
-
return true;
|
|
5139
|
-
}
|
|
5140
|
-
return this.group.canDisplayOverlay(event, position, 'content');
|
|
5821
|
+
canDisplayOverlay,
|
|
5822
|
+
getOverrideTarget: target ? () => target.model : undefined,
|
|
5823
|
+
});
|
|
5824
|
+
this.pointerDropTarget = pointerBackend.createDropTarget(this.element, {
|
|
5825
|
+
acceptedTargetZones: ['top', 'bottom', 'left', 'right', 'center'],
|
|
5826
|
+
canDisplayOverlay,
|
|
5827
|
+
getOverlayOutline: () => {
|
|
5828
|
+
var _a;
|
|
5829
|
+
return ((_a = accessor.options.theme) === null || _a === void 0 ? void 0 : _a.dndPanelOverlay) === 'group'
|
|
5830
|
+
? this.element.parentElement
|
|
5831
|
+
: null;
|
|
5141
5832
|
},
|
|
5833
|
+
className: 'dv-drop-target-content',
|
|
5142
5834
|
getOverrideTarget: target ? () => target.model : undefined,
|
|
5143
5835
|
});
|
|
5144
|
-
this.addDisposables(this.dropTarget);
|
|
5836
|
+
this.addDisposables(this.dropTarget, this.pointerDropTarget);
|
|
5145
5837
|
}
|
|
5146
5838
|
show() {
|
|
5147
5839
|
this.element.style.display = '';
|
|
@@ -5229,37 +5921,169 @@
|
|
|
5229
5921
|
}
|
|
5230
5922
|
}
|
|
5231
5923
|
|
|
5232
|
-
|
|
5233
|
-
|
|
5234
|
-
|
|
5235
|
-
|
|
5236
|
-
|
|
5237
|
-
|
|
5238
|
-
|
|
5239
|
-
|
|
5240
|
-
|
|
5241
|
-
|
|
5242
|
-
|
|
5243
|
-
|
|
5244
|
-
|
|
5245
|
-
|
|
5246
|
-
|
|
5247
|
-
|
|
5248
|
-
|
|
5249
|
-
|
|
5250
|
-
|
|
5251
|
-
this.
|
|
5252
|
-
|
|
5924
|
+
const DEFAULT_DELAY = 500;
|
|
5925
|
+
const DEFAULT_TOLERANCE = 8;
|
|
5926
|
+
/**
|
|
5927
|
+
* Passive — does not consume the pointer; movement past `tolerance`
|
|
5928
|
+
* cancels silently so a sibling `PointerDragSource` can take over.
|
|
5929
|
+
*/
|
|
5930
|
+
class LongPressDetector extends CompositeDisposable {
|
|
5931
|
+
constructor(element, options) {
|
|
5932
|
+
super();
|
|
5933
|
+
this.element = element;
|
|
5934
|
+
this.options = options;
|
|
5935
|
+
this._startX = 0;
|
|
5936
|
+
this._startY = 0;
|
|
5937
|
+
this.addDisposables(addDisposableListener(this.element, 'pointerdown', (e) => {
|
|
5938
|
+
this._onPointerDown(e);
|
|
5939
|
+
}));
|
|
5940
|
+
}
|
|
5941
|
+
_onPointerDown(event) {
|
|
5942
|
+
var _a, _b, _c, _d, _e;
|
|
5943
|
+
const touchOnly = (_a = this.options.touchOnly) !== null && _a !== void 0 ? _a : true;
|
|
5944
|
+
if (touchOnly &&
|
|
5945
|
+
event.pointerType !== 'touch' &&
|
|
5946
|
+
event.pointerType !== 'pen') {
|
|
5947
|
+
return;
|
|
5948
|
+
}
|
|
5949
|
+
// Defensive — supersede any in-flight press.
|
|
5950
|
+
this._cancelPending();
|
|
5951
|
+
this._pointerId = event.pointerId;
|
|
5952
|
+
this._startX = event.clientX;
|
|
5953
|
+
this._startY = event.clientY;
|
|
5954
|
+
const delay = (_b = this.options.delay) !== null && _b !== void 0 ? _b : DEFAULT_DELAY;
|
|
5955
|
+
const tolerance = (_c = this.options.tolerance) !== null && _c !== void 0 ? _c : DEFAULT_TOLERANCE;
|
|
5956
|
+
// Source's owning window — popout drags fire on their own window.
|
|
5957
|
+
const targetWindow = (_e = (_d = this.element.ownerDocument) === null || _d === void 0 ? void 0 : _d.defaultView) !== null && _e !== void 0 ? _e : window;
|
|
5958
|
+
this._timer = setTimeout(() => {
|
|
5959
|
+
this._timer = undefined;
|
|
5960
|
+
this._cancelPending();
|
|
5961
|
+
// Touch browsers synthesize a compatibility `contextmenu` event
|
|
5962
|
+
// for long-press. preventDefault on the original pointerdown is
|
|
5963
|
+
// too late (already dispatched), so install a one-shot
|
|
5964
|
+
// capture-phase guard for the next contextmenu. Without this,
|
|
5965
|
+
// consumers that don't preventDefault inside their onLongPress
|
|
5966
|
+
// (or that early-return before doing so) leak the browser's
|
|
5967
|
+
// native menu on top of theirs.
|
|
5968
|
+
this._installContextMenuGuard(targetWindow);
|
|
5969
|
+
// Same idea for `click`: when the user releases their finger
|
|
5970
|
+
// after the long-press, touch browsers dispatch a `click` to
|
|
5971
|
+
// the element the touch ended on (the source). Consumers
|
|
5972
|
+
// typically wire click to a primary action (e.g. tab activate,
|
|
5973
|
+
// tab-group chip collapse-toggle). Without this guard, the
|
|
5974
|
+
// long-press immediately fires both the context menu AND the
|
|
5975
|
+
// primary action — and the action's side effects (e.g. a chip
|
|
5976
|
+
// collapse animation) read as a screen wobble while the menu
|
|
5977
|
+
// is supposed to be open. Scoped to the source element so
|
|
5978
|
+
// clicks on menu items elsewhere remain effective.
|
|
5979
|
+
this._installClickGuard(targetWindow);
|
|
5980
|
+
this.options.onLongPress(event);
|
|
5981
|
+
}, delay);
|
|
5982
|
+
this._moveListener = addDisposableListener(targetWindow, 'pointermove', (moveEvent) => {
|
|
5983
|
+
if (moveEvent.pointerId !== this._pointerId) {
|
|
5984
|
+
return;
|
|
5985
|
+
}
|
|
5986
|
+
const dx = moveEvent.clientX - this._startX;
|
|
5987
|
+
const dy = moveEvent.clientY - this._startY;
|
|
5988
|
+
if (Math.hypot(dx, dy) > tolerance) {
|
|
5989
|
+
this._cancelPending();
|
|
5990
|
+
}
|
|
5991
|
+
});
|
|
5992
|
+
this._upListener = addDisposableListener(targetWindow, 'pointerup', (upEvent) => {
|
|
5993
|
+
if (upEvent.pointerId !== this._pointerId) {
|
|
5994
|
+
return;
|
|
5995
|
+
}
|
|
5996
|
+
this._cancelPending();
|
|
5997
|
+
});
|
|
5998
|
+
this._cancelListener = addDisposableListener(targetWindow, 'pointercancel', (cancelEvent) => {
|
|
5999
|
+
if (cancelEvent.pointerId !== this._pointerId) {
|
|
6000
|
+
return;
|
|
6001
|
+
}
|
|
6002
|
+
this._cancelPending();
|
|
6003
|
+
});
|
|
6004
|
+
}
|
|
6005
|
+
_installContextMenuGuard(targetWindow) {
|
|
6006
|
+
let guard;
|
|
6007
|
+
const timeout = setTimeout(() => guard === null || guard === void 0 ? void 0 : guard.dispose(), 500);
|
|
6008
|
+
guard = addDisposableListener(targetWindow, 'contextmenu', (event) => {
|
|
6009
|
+
event.preventDefault();
|
|
6010
|
+
clearTimeout(timeout);
|
|
6011
|
+
guard === null || guard === void 0 ? void 0 : guard.dispose();
|
|
6012
|
+
}, { capture: true });
|
|
6013
|
+
}
|
|
6014
|
+
_installClickGuard(targetWindow) {
|
|
6015
|
+
let guard;
|
|
6016
|
+
const timeout = setTimeout(() => guard === null || guard === void 0 ? void 0 : guard.dispose(), 500);
|
|
6017
|
+
guard = addDisposableListener(targetWindow, 'click', (event) => {
|
|
6018
|
+
// Only suppress clicks targeted at the long-pressed element
|
|
6019
|
+
// or its descendants. A user tap on a context menu item (or
|
|
6020
|
+
// anywhere else) still gets through unchanged.
|
|
6021
|
+
const target = event.target;
|
|
6022
|
+
if (target && this.element.contains(target)) {
|
|
6023
|
+
event.preventDefault();
|
|
6024
|
+
event.stopPropagation();
|
|
6025
|
+
}
|
|
6026
|
+
clearTimeout(timeout);
|
|
6027
|
+
guard === null || guard === void 0 ? void 0 : guard.dispose();
|
|
6028
|
+
}, { capture: true });
|
|
6029
|
+
}
|
|
6030
|
+
_cancelPending() {
|
|
6031
|
+
var _a, _b, _c;
|
|
6032
|
+
if (this._timer !== undefined) {
|
|
6033
|
+
clearTimeout(this._timer);
|
|
6034
|
+
this._timer = undefined;
|
|
6035
|
+
}
|
|
6036
|
+
this._pointerId = undefined;
|
|
6037
|
+
(_a = this._moveListener) === null || _a === void 0 ? void 0 : _a.dispose();
|
|
6038
|
+
(_b = this._upListener) === null || _b === void 0 ? void 0 : _b.dispose();
|
|
6039
|
+
(_c = this._cancelListener) === null || _c === void 0 ? void 0 : _c.dispose();
|
|
6040
|
+
this._moveListener = undefined;
|
|
6041
|
+
this._upListener = undefined;
|
|
6042
|
+
this._cancelListener = undefined;
|
|
6043
|
+
}
|
|
6044
|
+
dispose() {
|
|
6045
|
+
this._cancelPending();
|
|
6046
|
+
super.dispose();
|
|
6047
|
+
}
|
|
6048
|
+
}
|
|
6049
|
+
|
|
6050
|
+
function resolveDndCapabilities(options) {
|
|
6051
|
+
if (options.disableDnd) {
|
|
6052
|
+
return { html5: false, pointer: false, pointerHandlesMouse: false };
|
|
6053
|
+
}
|
|
6054
|
+
switch (options.dndStrategy) {
|
|
6055
|
+
case 'pointer':
|
|
6056
|
+
return { html5: false, pointer: true, pointerHandlesMouse: true };
|
|
6057
|
+
case 'html5':
|
|
6058
|
+
return { html5: true, pointer: false, pointerHandlesMouse: false };
|
|
6059
|
+
case 'auto':
|
|
6060
|
+
case undefined:
|
|
6061
|
+
default:
|
|
6062
|
+
// On touch-primary devices (phones / basic tablets) HTML5 DnD's
|
|
6063
|
+
// native long-press intercepts the gesture before our pointer
|
|
6064
|
+
// backend can react — Android Chrome launches a system drag with
|
|
6065
|
+
// its half-transparent thumbnail, and the long-press context menu
|
|
6066
|
+
// never opens. Disable HTML5 there so the pointer backend owns
|
|
6067
|
+
// every gesture. Hybrid devices (touchscreen laptops, Surface,
|
|
6068
|
+
// iPad with mouse) keep both backends — mouse uses HTML5, touch
|
|
6069
|
+
// falls back to whichever backend the underlying element wired.
|
|
6070
|
+
return isCoarsePrimaryInput$2()
|
|
6071
|
+
? { html5: false, pointer: true, pointerHandlesMouse: true }
|
|
6072
|
+
: { html5: true, pointer: true, pointerHandlesMouse: false };
|
|
5253
6073
|
}
|
|
5254
|
-
|
|
5255
|
-
|
|
5256
|
-
|
|
5257
|
-
|
|
5258
|
-
this.panelTransfer.clearData(PanelTransfer.prototype);
|
|
5259
|
-
},
|
|
5260
|
-
};
|
|
6074
|
+
}
|
|
6075
|
+
function isCoarsePrimaryInput$2() {
|
|
6076
|
+
if (typeof window === 'undefined' || !window.matchMedia) {
|
|
6077
|
+
return false;
|
|
5261
6078
|
}
|
|
6079
|
+
// Coarse pointer without any fine pointer = phone-class device. A laptop
|
|
6080
|
+
// touchscreen reports both, and we want HTML5 to remain available there
|
|
6081
|
+
// because a real mouse is also plugged in.
|
|
6082
|
+
const coarse = window.matchMedia('(pointer: coarse)').matches;
|
|
6083
|
+
const fine = window.matchMedia('(pointer: fine)').matches;
|
|
6084
|
+
return coarse && !fine;
|
|
5262
6085
|
}
|
|
6086
|
+
|
|
5263
6087
|
class Tab extends CompositeDisposable {
|
|
5264
6088
|
get element() {
|
|
5265
6089
|
return this._element;
|
|
@@ -5270,6 +6094,7 @@
|
|
|
5270
6094
|
this.accessor = accessor;
|
|
5271
6095
|
this.group = group;
|
|
5272
6096
|
this.content = undefined;
|
|
6097
|
+
this.panelTransfer = LocalSelectionTransfer.getInstance();
|
|
5273
6098
|
this._direction = 'horizontal';
|
|
5274
6099
|
this._onPointDown = new Emitter();
|
|
5275
6100
|
this.onPointerDown = this._onPointDown.event;
|
|
@@ -5281,114 +6106,106 @@
|
|
|
5281
6106
|
this.onDragStart = this._onDragStart.event;
|
|
5282
6107
|
this._onDragEnd = new Emitter();
|
|
5283
6108
|
this.onDragEnd = this._onDragEnd.event;
|
|
6109
|
+
const caps = resolveDndCapabilities(this.accessor.options);
|
|
5284
6110
|
this._element = document.createElement('div');
|
|
5285
6111
|
this._element.className = 'dv-tab';
|
|
5286
6112
|
this._element.tabIndex = 0;
|
|
5287
|
-
this._element.draggable =
|
|
6113
|
+
this._element.draggable = caps.html5;
|
|
5288
6114
|
toggleClass(this.element, 'dv-inactive-tab', true);
|
|
5289
|
-
|
|
5290
|
-
|
|
6115
|
+
const canDisplayOverlay = (event, position) => {
|
|
6116
|
+
var _a;
|
|
6117
|
+
if (this.group.locked) {
|
|
6118
|
+
return false;
|
|
6119
|
+
}
|
|
6120
|
+
const data = getPanelData();
|
|
6121
|
+
if (data && this.accessor.id === data.viewId) {
|
|
6122
|
+
// Smooth-reorder takes over the in-flight visual when active,
|
|
6123
|
+
// so individual tab overlays are suppressed for internal drags.
|
|
6124
|
+
if (((_a = this.accessor.options.theme) === null || _a === void 0 ? void 0 : _a.tabAnimation) === 'smooth') {
|
|
6125
|
+
return false;
|
|
6126
|
+
}
|
|
6127
|
+
return true;
|
|
6128
|
+
}
|
|
6129
|
+
return this.group.model.canDisplayOverlay(event, position, 'tab');
|
|
6130
|
+
};
|
|
6131
|
+
this.dropTarget = html5Backend.createDropTarget(this._element, {
|
|
5291
6132
|
acceptedTargetZones: ['left', 'right'],
|
|
5292
6133
|
overlayModel: this._buildOverlayModel(),
|
|
5293
|
-
canDisplayOverlay
|
|
6134
|
+
canDisplayOverlay,
|
|
6135
|
+
getOverrideTarget: () => { var _a; return (_a = group.model.dropTargetContainer) === null || _a === void 0 ? void 0 : _a.model; },
|
|
6136
|
+
});
|
|
6137
|
+
this.pointerDropTarget = pointerBackend.createDropTarget(this._element, {
|
|
6138
|
+
acceptedTargetZones: ['left', 'right'],
|
|
6139
|
+
overlayModel: this._buildOverlayModel(),
|
|
6140
|
+
canDisplayOverlay,
|
|
6141
|
+
getOverrideTarget: () => { var _a; return (_a = group.model.dropTargetContainer) === null || _a === void 0 ? void 0 : _a.model; },
|
|
6142
|
+
});
|
|
6143
|
+
const sharedDragOptions = {
|
|
6144
|
+
getData: () => {
|
|
6145
|
+
this.panelTransfer.setData([
|
|
6146
|
+
new PanelTransfer(this.accessor.id, this.group.id, this.panel.id),
|
|
6147
|
+
], PanelTransfer.prototype);
|
|
6148
|
+
return {
|
|
6149
|
+
dispose: () => {
|
|
6150
|
+
this.panelTransfer.clearData(PanelTransfer.prototype);
|
|
6151
|
+
},
|
|
6152
|
+
};
|
|
6153
|
+
},
|
|
6154
|
+
// 30/-10 matches the HTML5 setDragImage offset that has been
|
|
6155
|
+
// shipped for years; pointer backend wraps in PointerGhost,
|
|
6156
|
+
// HTML5 backend feeds into setDragImage.
|
|
6157
|
+
createGhost: () => ({
|
|
6158
|
+
element: this._buildGhostElement(),
|
|
6159
|
+
offsetX: 30,
|
|
6160
|
+
offsetY: -10,
|
|
6161
|
+
}),
|
|
6162
|
+
onDragStart: (event) => {
|
|
5294
6163
|
var _a;
|
|
5295
|
-
|
|
5296
|
-
|
|
5297
|
-
|
|
5298
|
-
|
|
5299
|
-
|
|
5300
|
-
|
|
5301
|
-
|
|
5302
|
-
|
|
5303
|
-
// (both same-group and cross-group) via
|
|
5304
|
-
// animation. Suppress the per-tab overlay so
|
|
5305
|
-
// the tab is dropped *beside* rather than *on*.
|
|
5306
|
-
return false;
|
|
5307
|
-
}
|
|
5308
|
-
return true;
|
|
6164
|
+
this._onDragStart.fire(event);
|
|
6165
|
+
if (!(event instanceof PointerEvent) &&
|
|
6166
|
+
((_a = this.accessor.options.theme) === null || _a === void 0 ? void 0 : _a.tabAnimation) === 'smooth') {
|
|
6167
|
+
// Delay collapse to next frame so the browser
|
|
6168
|
+
// captures the full drag image first.
|
|
6169
|
+
requestAnimationFrame(() => {
|
|
6170
|
+
toggleClass(this.element, 'dv-tab--dragging', true);
|
|
6171
|
+
});
|
|
5309
6172
|
}
|
|
5310
|
-
return this.group.model.canDisplayOverlay(event, position, 'tab');
|
|
5311
6173
|
},
|
|
5312
|
-
|
|
5313
|
-
|
|
5314
|
-
|
|
6174
|
+
onDragEnd: (event) => {
|
|
6175
|
+
this._onDragEnd.fire(event);
|
|
6176
|
+
},
|
|
6177
|
+
};
|
|
6178
|
+
this.html5DragSource = html5Backend.createDragSource(this._element, Object.assign(Object.assign({}, sharedDragOptions), { disabled: !caps.html5 }));
|
|
6179
|
+
this.pointerDragSource = pointerBackend.createDragSource(this._element, Object.assign(Object.assign({}, sharedDragOptions), { disabled: !caps.pointer, touchOnly: !caps.pointerHandlesMouse, isCancelled: () => !resolveDndCapabilities(this.accessor.options).pointer }));
|
|
6180
|
+
// Both droptargets feed the same downstream stream; consumers don't
|
|
6181
|
+
// need to know which path produced the overlay.
|
|
6182
|
+
this.onWillShowOverlay = exports.DockviewEvent.any(this.dropTarget.onWillShowOverlay, this.pointerDropTarget.onWillShowOverlay);
|
|
5315
6183
|
this.addDisposables(this._onPointDown, this._onTabClick, this._onDropped, this._onDragStart, this._onDragEnd, this.accessor.onDidOptionsChange(() => {
|
|
5316
|
-
this.
|
|
5317
|
-
|
|
5318
|
-
|
|
5319
|
-
|
|
5320
|
-
|
|
5321
|
-
|
|
5322
|
-
const isVertical = this._direction === 'vertical';
|
|
5323
|
-
/**
|
|
5324
|
-
* Properties to skip when copying computed styles for a
|
|
5325
|
-
* vertical tab ghost. `writing-mode` is excluded so we
|
|
5326
|
-
* can force `horizontal-tb`. Size and margin logical
|
|
5327
|
-
* properties are excluded because their physical meaning
|
|
5328
|
-
* flips when writing-mode changes, which would produce
|
|
5329
|
-
* incorrect dimensions.
|
|
5330
|
-
*/
|
|
5331
|
-
const verticalSkip = new Set([
|
|
5332
|
-
'writing-mode',
|
|
5333
|
-
'inline-size',
|
|
5334
|
-
'block-size',
|
|
5335
|
-
'min-inline-size',
|
|
5336
|
-
'min-block-size',
|
|
5337
|
-
'max-inline-size',
|
|
5338
|
-
'max-block-size',
|
|
5339
|
-
'margin-inline',
|
|
5340
|
-
'margin-inline-start',
|
|
5341
|
-
'margin-inline-end',
|
|
5342
|
-
'margin-block',
|
|
5343
|
-
'margin-block-start',
|
|
5344
|
-
'margin-block-end',
|
|
5345
|
-
'padding-inline',
|
|
5346
|
-
'padding-inline-start',
|
|
5347
|
-
'padding-inline-end',
|
|
5348
|
-
'padding-block',
|
|
5349
|
-
'padding-block-start',
|
|
5350
|
-
'padding-block-end',
|
|
5351
|
-
]);
|
|
5352
|
-
Array.from(style).forEach((key) => {
|
|
5353
|
-
if (isVertical && verticalSkip.has(key)) {
|
|
5354
|
-
return;
|
|
5355
|
-
}
|
|
5356
|
-
newNode.style.setProperty(key, style.getPropertyValue(key), style.getPropertyPriority(key));
|
|
5357
|
-
});
|
|
5358
|
-
if (isVertical) {
|
|
5359
|
-
// Force horizontal text flow and swap the physical
|
|
5360
|
-
// dimensions so the ghost appears as a horizontal tab.
|
|
5361
|
-
newNode.style.setProperty('writing-mode', 'horizontal-tb');
|
|
5362
|
-
newNode.style.setProperty('width', style.height);
|
|
5363
|
-
newNode.style.setProperty('height', style.width);
|
|
5364
|
-
}
|
|
5365
|
-
newNode.style.position = 'absolute';
|
|
5366
|
-
newNode.classList.add('dv-tab-ghost-drag');
|
|
5367
|
-
addGhostImage(event.dataTransfer, newNode, {
|
|
5368
|
-
y: -10,
|
|
5369
|
-
x: 30,
|
|
5370
|
-
});
|
|
5371
|
-
}
|
|
5372
|
-
this._onDragStart.fire(event);
|
|
5373
|
-
if (((_a = this.accessor.options.theme) === null || _a === void 0 ? void 0 : _a.tabAnimation) === 'smooth') {
|
|
5374
|
-
// Delay collapse to next frame so the browser
|
|
5375
|
-
// captures the full drag image first
|
|
5376
|
-
requestAnimationFrame(() => {
|
|
5377
|
-
toggleClass(this.element, 'dv-tab--dragging', true);
|
|
5378
|
-
});
|
|
5379
|
-
}
|
|
5380
|
-
}), addDisposableListener(this._element, 'dragend', (event) => {
|
|
6184
|
+
const model = this._buildOverlayModel();
|
|
6185
|
+
this.dropTarget.setOverlayModel(model);
|
|
6186
|
+
this.pointerDropTarget.setOverlayModel(model);
|
|
6187
|
+
}), addDisposableListener(this._element, 'dragend', () => {
|
|
6188
|
+
// The shared onDragEnd handler already fires _onDragEnd via
|
|
6189
|
+
// the HTML5 backend; just strip the dragging class here.
|
|
5381
6190
|
toggleClass(this.element, 'dv-tab--dragging', false);
|
|
5382
|
-
|
|
5383
|
-
}), this.dragHandler, addDisposableListener(this._element, 'pointerdown', (event) => {
|
|
6191
|
+
}), this.html5DragSource, addDisposableListener(this._element, 'pointerdown', (event) => {
|
|
5384
6192
|
this._onPointDown.fire(event);
|
|
5385
6193
|
}), addDisposableListener(this._element, 'click', (event) => {
|
|
5386
6194
|
this._onTabClick.fire(event);
|
|
5387
6195
|
}), addDisposableListener(this._element, 'contextmenu', (event) => {
|
|
5388
6196
|
this.accessor.contextMenuController.show(this.panel, this.group, event);
|
|
6197
|
+
}), new LongPressDetector(this._element, {
|
|
6198
|
+
onLongPress: (event) => {
|
|
6199
|
+
// Don't let a subsequent finger move arm a drag on top
|
|
6200
|
+
// of the just-opened menu.
|
|
6201
|
+
this.pointerDragSource.cancelPending();
|
|
6202
|
+
this.accessor.contextMenuController.show(this.panel, this.group, event);
|
|
6203
|
+
},
|
|
5389
6204
|
}), this.dropTarget.onDrop((event) => {
|
|
5390
6205
|
this._onDropped.fire(event);
|
|
5391
|
-
}), this.
|
|
6206
|
+
}), this.pointerDropTarget.onDrop((event) => {
|
|
6207
|
+
this._onDropped.fire(event);
|
|
6208
|
+
}), this.dropTarget, this.pointerDropTarget, this.pointerDragSource);
|
|
5392
6209
|
}
|
|
5393
6210
|
setActive(isActive) {
|
|
5394
6211
|
toggleClass(this.element, 'dv-active-tab', isActive);
|
|
@@ -5418,11 +6235,60 @@
|
|
|
5418
6235
|
}
|
|
5419
6236
|
setDirection(direction) {
|
|
5420
6237
|
this._direction = direction;
|
|
5421
|
-
|
|
6238
|
+
const zones = direction === 'vertical' ? ['top', 'bottom'] : ['left', 'right'];
|
|
6239
|
+
this.dropTarget.setTargetZones(zones);
|
|
6240
|
+
this.pointerDropTarget.setTargetZones(zones);
|
|
5422
6241
|
}
|
|
5423
6242
|
updateDragAndDropState() {
|
|
5424
|
-
|
|
5425
|
-
this.
|
|
6243
|
+
const caps = resolveDndCapabilities(this.accessor.options);
|
|
6244
|
+
this._element.draggable = caps.html5;
|
|
6245
|
+
this.html5DragSource.setDisabled(!caps.html5);
|
|
6246
|
+
this.pointerDragSource.setDisabled(!caps.pointer);
|
|
6247
|
+
this.pointerDragSource.setTouchOnly(!caps.pointerHandlesMouse);
|
|
6248
|
+
}
|
|
6249
|
+
/**
|
|
6250
|
+
* Vertical tabs are flipped to horizontal so the ghost stays readable
|
|
6251
|
+
* during the drag rather than appearing sideways-rotated.
|
|
6252
|
+
*/
|
|
6253
|
+
_buildGhostElement() {
|
|
6254
|
+
const style = getComputedStyle(this.element);
|
|
6255
|
+
const newNode = this.element.cloneNode(true);
|
|
6256
|
+
const isVertical = this._direction === 'vertical';
|
|
6257
|
+
const verticalSkip = new Set([
|
|
6258
|
+
'writing-mode',
|
|
6259
|
+
'inline-size',
|
|
6260
|
+
'block-size',
|
|
6261
|
+
'min-inline-size',
|
|
6262
|
+
'min-block-size',
|
|
6263
|
+
'max-inline-size',
|
|
6264
|
+
'max-block-size',
|
|
6265
|
+
'margin-inline',
|
|
6266
|
+
'margin-inline-start',
|
|
6267
|
+
'margin-inline-end',
|
|
6268
|
+
'margin-block',
|
|
6269
|
+
'margin-block-start',
|
|
6270
|
+
'margin-block-end',
|
|
6271
|
+
'padding-inline',
|
|
6272
|
+
'padding-inline-start',
|
|
6273
|
+
'padding-inline-end',
|
|
6274
|
+
'padding-block',
|
|
6275
|
+
'padding-block-start',
|
|
6276
|
+
'padding-block-end',
|
|
6277
|
+
]);
|
|
6278
|
+
Array.from(style).forEach((key) => {
|
|
6279
|
+
if (isVertical && verticalSkip.has(key)) {
|
|
6280
|
+
return;
|
|
6281
|
+
}
|
|
6282
|
+
newNode.style.setProperty(key, style.getPropertyValue(key), style.getPropertyPriority(key));
|
|
6283
|
+
});
|
|
6284
|
+
if (isVertical) {
|
|
6285
|
+
newNode.style.setProperty('writing-mode', 'horizontal-tb');
|
|
6286
|
+
newNode.style.setProperty('width', style.height);
|
|
6287
|
+
newNode.style.setProperty('height', style.width);
|
|
6288
|
+
}
|
|
6289
|
+
newNode.style.position = 'absolute';
|
|
6290
|
+
newNode.classList.add('dv-tab-ghost-drag');
|
|
6291
|
+
return newNode;
|
|
5426
6292
|
}
|
|
5427
6293
|
}
|
|
5428
6294
|
|
|
@@ -5430,6 +6296,7 @@
|
|
|
5430
6296
|
get kind() {
|
|
5431
6297
|
return this.options.kind;
|
|
5432
6298
|
}
|
|
6299
|
+
/** Narrow with `instanceof DragEvent` before reading `dataTransfer`. */
|
|
5433
6300
|
get nativeEvent() {
|
|
5434
6301
|
return this.event.nativeEvent;
|
|
5435
6302
|
}
|
|
@@ -5460,103 +6327,202 @@
|
|
|
5460
6327
|
}
|
|
5461
6328
|
}
|
|
5462
6329
|
|
|
5463
|
-
|
|
5464
|
-
|
|
5465
|
-
|
|
5466
|
-
|
|
5467
|
-
|
|
5468
|
-
this.panelTransfer = LocalSelectionTransfer.getInstance();
|
|
5469
|
-
this.addDisposables(addDisposableListener(element, 'pointerdown', (e) => {
|
|
5470
|
-
if (e.shiftKey) {
|
|
5471
|
-
/**
|
|
5472
|
-
* You cannot call e.preventDefault() because that will prevent drag events from firing
|
|
5473
|
-
* but we also need to stop any group overlay drag events from occuring
|
|
5474
|
-
* Use a custom event marker that can be checked by the overlay drag events
|
|
5475
|
-
*/
|
|
5476
|
-
quasiPreventDefault(e);
|
|
5477
|
-
}
|
|
5478
|
-
}, true));
|
|
5479
|
-
}
|
|
5480
|
-
isCancelled(_event) {
|
|
5481
|
-
if (this.group.api.location.type === 'floating' && !_event.shiftKey) {
|
|
5482
|
-
return true;
|
|
5483
|
-
}
|
|
5484
|
-
if (this.group.api.location.type === 'edge' && this.group.size === 0) {
|
|
5485
|
-
return true;
|
|
5486
|
-
}
|
|
5487
|
-
return false;
|
|
5488
|
-
}
|
|
5489
|
-
getData(dragEvent) {
|
|
5490
|
-
const dataTransfer = dragEvent.dataTransfer;
|
|
5491
|
-
this.panelTransfer.setData([new PanelTransfer(this.accessor.id, this.group.id, null)], PanelTransfer.prototype);
|
|
5492
|
-
const style = window.getComputedStyle(this.el);
|
|
5493
|
-
const bgColor = style.getPropertyValue('--dv-activegroup-visiblepanel-tab-background-color');
|
|
5494
|
-
const color = style.getPropertyValue('--dv-activegroup-visiblepanel-tab-color');
|
|
5495
|
-
if (dataTransfer) {
|
|
5496
|
-
const ghostElement = document.createElement('div');
|
|
5497
|
-
ghostElement.style.backgroundColor = bgColor;
|
|
5498
|
-
ghostElement.style.color = color;
|
|
5499
|
-
ghostElement.style.padding = '2px 8px';
|
|
5500
|
-
ghostElement.style.height = '24px';
|
|
5501
|
-
ghostElement.style.fontSize = '11px';
|
|
5502
|
-
ghostElement.style.lineHeight = '20px';
|
|
5503
|
-
ghostElement.style.borderRadius = '12px';
|
|
5504
|
-
ghostElement.style.position = 'absolute';
|
|
5505
|
-
ghostElement.style.pointerEvents = 'none';
|
|
5506
|
-
ghostElement.style.top = '-9999px';
|
|
5507
|
-
ghostElement.textContent = `Multiple Panels (${this.group.size})`;
|
|
5508
|
-
addGhostImage(dataTransfer, ghostElement, { y: -10, x: 30 });
|
|
5509
|
-
}
|
|
5510
|
-
return {
|
|
5511
|
-
dispose: () => {
|
|
5512
|
-
this.panelTransfer.clearData(PanelTransfer.prototype);
|
|
5513
|
-
},
|
|
5514
|
-
};
|
|
5515
|
-
}
|
|
5516
|
-
}
|
|
5517
|
-
|
|
6330
|
+
// Floating-group redock via touch: require a deliberate long press so the
|
|
6331
|
+
// "move the float around" gesture doesn't double-trigger the redock ghost.
|
|
6332
|
+
// Infinity pressTolerance disables the pre-arm flick override; any motion
|
|
6333
|
+
// during the wait is treated as drag-the-float, not redock intent.
|
|
6334
|
+
const FLOATING_REDOCK_INITIATION_DELAY_MS = 500;
|
|
5518
6335
|
class VoidContainer extends CompositeDisposable {
|
|
5519
6336
|
get element() {
|
|
5520
6337
|
return this._element;
|
|
5521
6338
|
}
|
|
5522
6339
|
constructor(accessor, group) {
|
|
6340
|
+
var _a, _b;
|
|
5523
6341
|
super();
|
|
5524
6342
|
this.accessor = accessor;
|
|
5525
6343
|
this.group = group;
|
|
6344
|
+
this.panelTransfer = LocalSelectionTransfer.getInstance();
|
|
5526
6345
|
this._onDrop = new Emitter();
|
|
5527
6346
|
this.onDrop = this._onDrop.event;
|
|
5528
6347
|
this._onDragStart = new Emitter();
|
|
5529
6348
|
this.onDragStart = this._onDragStart.event;
|
|
6349
|
+
const caps = resolveDndCapabilities(this.accessor.options);
|
|
5530
6350
|
this._element = document.createElement('div');
|
|
5531
6351
|
this._element.className = 'dv-void-container';
|
|
5532
|
-
this._element.draggable =
|
|
5533
|
-
toggleClass(this._element, 'dv-draggable',
|
|
6352
|
+
this._element.draggable = caps.html5;
|
|
6353
|
+
toggleClass(this._element, 'dv-draggable', caps.html5 || caps.pointer);
|
|
5534
6354
|
this.addDisposables(this._onDrop, this._onDragStart, addDisposableListener(this._element, 'pointerdown', () => {
|
|
5535
6355
|
this.accessor.doSetGroupActive(this.group);
|
|
5536
|
-
})
|
|
5537
|
-
|
|
5538
|
-
|
|
6356
|
+
}),
|
|
6357
|
+
// Shift+pointerdown marks the event so the group's overlay
|
|
6358
|
+
// drag (move-by-floating) sees it was consumed and doesn't
|
|
6359
|
+
// fire alongside the HTML5 drag. quasiPreventDefault sets the
|
|
6360
|
+
// marker without calling preventDefault — that would also
|
|
6361
|
+
// block dragstart, which we need to fire.
|
|
6362
|
+
addDisposableListener(this._element, 'pointerdown', (e) => {
|
|
6363
|
+
if (e.shiftKey) {
|
|
6364
|
+
quasiPreventDefault(e);
|
|
6365
|
+
}
|
|
6366
|
+
}, true));
|
|
6367
|
+
const canDisplayOverlay = (event, position) => {
|
|
6368
|
+
if (this.group.api.locked) {
|
|
6369
|
+
// Dropping on the void/header space adds the panel
|
|
6370
|
+
// to this group, which `locked` is meant to prevent
|
|
6371
|
+
// (both `true` and `'no-drop-target'`).
|
|
6372
|
+
return false;
|
|
6373
|
+
}
|
|
6374
|
+
const data = getPanelData();
|
|
6375
|
+
if (data && this.accessor.id === data.viewId) {
|
|
6376
|
+
return true;
|
|
6377
|
+
}
|
|
6378
|
+
return group.model.canDisplayOverlay(event, position, 'header_space');
|
|
6379
|
+
};
|
|
6380
|
+
this.dropTarget = html5Backend.createDropTarget(this._element, {
|
|
5539
6381
|
acceptedTargetZones: ['center'],
|
|
5540
|
-
canDisplayOverlay
|
|
5541
|
-
const data = getPanelData();
|
|
5542
|
-
if (data && this.accessor.id === data.viewId) {
|
|
5543
|
-
return true;
|
|
5544
|
-
}
|
|
5545
|
-
return group.model.canDisplayOverlay(event, position, 'header_space');
|
|
5546
|
-
},
|
|
6382
|
+
canDisplayOverlay,
|
|
5547
6383
|
getOverrideTarget: () => { var _a; return (_a = group.model.dropTargetContainer) === null || _a === void 0 ? void 0 : _a.model; },
|
|
5548
6384
|
});
|
|
5549
|
-
this.
|
|
5550
|
-
|
|
5551
|
-
|
|
5552
|
-
|
|
6385
|
+
this.pointerDropTarget = pointerBackend.createDropTarget(this._element, {
|
|
6386
|
+
acceptedTargetZones: ['center'],
|
|
6387
|
+
canDisplayOverlay,
|
|
6388
|
+
getOverrideTarget: () => { var _a; return (_a = group.model.dropTargetContainer) === null || _a === void 0 ? void 0 : _a.model; },
|
|
6389
|
+
});
|
|
6390
|
+
const buildMultiPanelsGhost = () => {
|
|
6391
|
+
const ghostEl = document.createElement('div');
|
|
6392
|
+
const style = window.getComputedStyle(this._element);
|
|
6393
|
+
const bgColor = style.getPropertyValue('--dv-activegroup-visiblepanel-tab-background-color');
|
|
6394
|
+
const color = style.getPropertyValue('--dv-activegroup-visiblepanel-tab-color');
|
|
6395
|
+
ghostEl.style.backgroundColor = bgColor;
|
|
6396
|
+
ghostEl.style.color = color;
|
|
6397
|
+
ghostEl.style.padding = '2px 8px';
|
|
6398
|
+
ghostEl.style.height = '24px';
|
|
6399
|
+
ghostEl.style.fontSize = '11px';
|
|
6400
|
+
ghostEl.style.lineHeight = '20px';
|
|
6401
|
+
ghostEl.style.borderRadius = '12px';
|
|
6402
|
+
ghostEl.style.whiteSpace = 'nowrap';
|
|
6403
|
+
ghostEl.style.boxSizing = 'border-box';
|
|
6404
|
+
// HTML5 setDragImage snapshots the element as appended to the
|
|
6405
|
+
// document; a default block-level div would stretch to the
|
|
6406
|
+
// body's width and render as a viewport-wide bar.
|
|
6407
|
+
ghostEl.style.display = 'inline-block';
|
|
6408
|
+
ghostEl.textContent = `Multiple Panels (${this.group.size})`;
|
|
6409
|
+
return ghostEl;
|
|
6410
|
+
};
|
|
6411
|
+
const buildGhostSpec = () => {
|
|
6412
|
+
const createGhost = this.accessor.options.createGroupDragGhostComponent;
|
|
6413
|
+
if (createGhost) {
|
|
6414
|
+
const renderer = createGhost(this.group);
|
|
6415
|
+
renderer.init({
|
|
6416
|
+
group: this.group,
|
|
6417
|
+
api: this.accessor.api,
|
|
6418
|
+
});
|
|
6419
|
+
return {
|
|
6420
|
+
element: renderer.element,
|
|
6421
|
+
offsetX: 30,
|
|
6422
|
+
offsetY: -10,
|
|
6423
|
+
dispose: renderer.dispose
|
|
6424
|
+
? () => { var _a; return (_a = renderer.dispose) === null || _a === void 0 ? void 0 : _a.call(renderer); }
|
|
6425
|
+
: undefined,
|
|
6426
|
+
};
|
|
6427
|
+
}
|
|
6428
|
+
return {
|
|
6429
|
+
element: buildMultiPanelsGhost(),
|
|
6430
|
+
offsetX: 30,
|
|
6431
|
+
offsetY: -10,
|
|
6432
|
+
};
|
|
6433
|
+
};
|
|
6434
|
+
const sharedDragOptions = {
|
|
6435
|
+
getData: () => {
|
|
6436
|
+
this.panelTransfer.setData([new PanelTransfer(this.accessor.id, this.group.id, null)], PanelTransfer.prototype);
|
|
6437
|
+
return {
|
|
6438
|
+
dispose: () => {
|
|
6439
|
+
this.panelTransfer.clearData(PanelTransfer.prototype);
|
|
6440
|
+
},
|
|
6441
|
+
};
|
|
6442
|
+
},
|
|
6443
|
+
createGhost: buildGhostSpec,
|
|
6444
|
+
onDragStart: (event) => {
|
|
6445
|
+
this._onDragStart.fire(event);
|
|
6446
|
+
},
|
|
6447
|
+
};
|
|
6448
|
+
this.html5DragSource = html5Backend.createDragSource(this._element, Object.assign(Object.assign({}, sharedDragOptions), { disabled: !caps.html5, isCancelled: (event) => {
|
|
6449
|
+
// HTML5: floating groups need shift+drag as the explicit
|
|
6450
|
+
// detach gesture (otherwise click-and-drag conflicts with
|
|
6451
|
+
// moving the floating group itself).
|
|
6452
|
+
if (this.group.api.location.type === 'floating' &&
|
|
6453
|
+
!event.shiftKey) {
|
|
6454
|
+
return true;
|
|
6455
|
+
}
|
|
6456
|
+
if (this.group.api.location.type === 'edge' &&
|
|
6457
|
+
this.group.size === 0) {
|
|
6458
|
+
return true;
|
|
6459
|
+
}
|
|
6460
|
+
return false;
|
|
6461
|
+
} }));
|
|
6462
|
+
const isFloating = () => { var _a, _b, _c; return ((_c = (_b = (_a = this.group) === null || _a === void 0 ? void 0 : _a.api) === null || _b === void 0 ? void 0 : _b.location) === null || _c === void 0 ? void 0 : _c.type) === 'floating'; };
|
|
6463
|
+
this.pointerDragSource = pointerBackend.createDragSource(this._element, Object.assign(Object.assign({}, sharedDragOptions), { disabled: !caps.pointer, touchOnly: !caps.pointerHandlesMouse,
|
|
6464
|
+
// Floating groups share this element with the overlay's
|
|
6465
|
+
// move-the-float drag. Without a longer hold + tolerance
|
|
6466
|
+
// override, both gestures commit simultaneously and the
|
|
6467
|
+
// user sees the float follow their finger *and* a ghost.
|
|
6468
|
+
touchInitiationDelay: () => isFloating() ? FLOATING_REDOCK_INITIATION_DELAY_MS : 250, pressTolerance: () => (isFloating() ? Infinity : 8), isCancelled: () => {
|
|
6469
|
+
if (!resolveDndCapabilities(this.accessor.options).pointer) {
|
|
6470
|
+
return true;
|
|
6471
|
+
}
|
|
6472
|
+
// Pointer: long-press IS the deliberate gesture, so
|
|
6473
|
+
// floating groups don't need the shift gate.
|
|
6474
|
+
if (this.group.api.location.type === 'edge' &&
|
|
6475
|
+
this.group.size === 0) {
|
|
6476
|
+
return true;
|
|
6477
|
+
}
|
|
6478
|
+
return false;
|
|
6479
|
+
}, onDragStart: (event) => {
|
|
6480
|
+
var _a;
|
|
6481
|
+
// Redock just committed — abort any in-flight overlay
|
|
6482
|
+
// move so the float stops following the finger while
|
|
6483
|
+
// the ghost takes over.
|
|
6484
|
+
(_a = this.getFloatingOverlay()) === null || _a === void 0 ? void 0 : _a.cancelPendingDrag();
|
|
6485
|
+
this._onDragStart.fire(event);
|
|
6486
|
+
} }));
|
|
6487
|
+
// Mirror direction: once the overlay's move-the-float gesture has
|
|
6488
|
+
// actually moved something, cancel the pending redock arm so the
|
|
6489
|
+
// ghost doesn't appear mid-drag if the user holds past 500ms.
|
|
6490
|
+
const overlayMoveSub = new MutableDisposable();
|
|
6491
|
+
const refreshOverlayMoveSub = () => {
|
|
6492
|
+
const overlay = this.getFloatingOverlay();
|
|
6493
|
+
overlayMoveSub.value = overlay
|
|
6494
|
+
? overlay.onDidStartMoving(() => {
|
|
6495
|
+
this.pointerDragSource.cancelPending();
|
|
6496
|
+
})
|
|
6497
|
+
: exports.DockviewDisposable.NONE;
|
|
6498
|
+
};
|
|
6499
|
+
refreshOverlayMoveSub();
|
|
6500
|
+
this.addDisposables(overlayMoveSub);
|
|
6501
|
+
const locationChange = (_b = (_a = this.group) === null || _a === void 0 ? void 0 : _a.api) === null || _b === void 0 ? void 0 : _b.onDidLocationChange;
|
|
6502
|
+
if (locationChange) {
|
|
6503
|
+
this.addDisposables(locationChange(refreshOverlayMoveSub));
|
|
6504
|
+
}
|
|
6505
|
+
this.onWillShowOverlay = exports.DockviewEvent.any(this.dropTarget.onWillShowOverlay, this.pointerDropTarget.onWillShowOverlay);
|
|
6506
|
+
this.addDisposables(this.html5DragSource, this.dropTarget.onDrop((event) => {
|
|
6507
|
+
this._onDrop.fire(event);
|
|
6508
|
+
}), this.pointerDropTarget.onDrop((event) => {
|
|
5553
6509
|
this._onDrop.fire(event);
|
|
5554
|
-
}), this.dropTarget);
|
|
6510
|
+
}), this.dropTarget, this.pointerDropTarget, this.pointerDragSource);
|
|
5555
6511
|
}
|
|
5556
6512
|
updateDragAndDropState() {
|
|
5557
|
-
|
|
5558
|
-
|
|
5559
|
-
|
|
6513
|
+
const caps = resolveDndCapabilities(this.accessor.options);
|
|
6514
|
+
this._element.draggable = caps.html5;
|
|
6515
|
+
toggleClass(this._element, 'dv-draggable', caps.html5 || caps.pointer);
|
|
6516
|
+
this.html5DragSource.setDisabled(!caps.html5);
|
|
6517
|
+
this.pointerDragSource.setDisabled(!caps.pointer);
|
|
6518
|
+
this.pointerDragSource.setTouchOnly(!caps.pointerHandlesMouse);
|
|
6519
|
+
}
|
|
6520
|
+
getFloatingOverlay() {
|
|
6521
|
+
var _a, _b;
|
|
6522
|
+
if (!this.group) {
|
|
6523
|
+
return undefined;
|
|
6524
|
+
}
|
|
6525
|
+
return (_b = (_a = this.accessor.floatingGroups) === null || _a === void 0 ? void 0 : _a.find((fg) => fg.group === this.group)) === null || _b === void 0 ? void 0 : _b.overlay;
|
|
5560
6526
|
}
|
|
5561
6527
|
}
|
|
5562
6528
|
|
|
@@ -5812,6 +6778,14 @@
|
|
|
5812
6778
|
return (palette !== null && palette !== void 0 ? palette : getFallbackPalette()).resolveValue(color);
|
|
5813
6779
|
}
|
|
5814
6780
|
|
|
6781
|
+
/**
|
|
6782
|
+
* Visual chip for a tab group. Owns the DOM element, label, click /
|
|
6783
|
+
* context-menu interactions, and exposes a long-press gesture as a
|
|
6784
|
+
* second `onContextMenu` source. Drag-and-drop wiring lives in
|
|
6785
|
+
* `TabGroupManager` — the manager constructs the drag sources on this
|
|
6786
|
+
* chip's element so it can include tabs-list context (custom group
|
|
6787
|
+
* drag image, tab-group transfer payload).
|
|
6788
|
+
*/
|
|
5815
6789
|
class TabGroupChip extends CompositeDisposable {
|
|
5816
6790
|
get element() {
|
|
5817
6791
|
return this._element;
|
|
@@ -5822,22 +6796,22 @@
|
|
|
5822
6796
|
this._onClick = new Emitter();
|
|
5823
6797
|
this.onClick = this._onClick.event;
|
|
5824
6798
|
this._onContextMenu = new Emitter();
|
|
6799
|
+
/** Fires on right-click and on touch long-press. */
|
|
5825
6800
|
this.onContextMenu = this._onContextMenu.event;
|
|
5826
|
-
this._onDragStart = new Emitter();
|
|
5827
|
-
this.onDragStart = this._onDragStart.event;
|
|
5828
6801
|
this._element = document.createElement('div');
|
|
5829
6802
|
this._element.className = 'dv-tab-group-chip';
|
|
5830
6803
|
this._element.tabIndex = 0;
|
|
5831
|
-
this._element.draggable = true;
|
|
5832
6804
|
this._label = document.createElement('span');
|
|
5833
6805
|
this._label.className = 'dv-tab-group-chip-label';
|
|
5834
6806
|
this._element.appendChild(this._label);
|
|
5835
|
-
this.addDisposables(this._onClick, this._onContextMenu,
|
|
6807
|
+
this.addDisposables(this._onClick, this._onContextMenu, new LongPressDetector(this._element, {
|
|
6808
|
+
onLongPress: (event) => {
|
|
6809
|
+
this._onContextMenu.fire(event);
|
|
6810
|
+
},
|
|
6811
|
+
}), addDisposableListener(this._element, 'click', (event) => {
|
|
5836
6812
|
this._onClick.fire(event);
|
|
5837
6813
|
}), addDisposableListener(this._element, 'contextmenu', (event) => {
|
|
5838
6814
|
this._onContextMenu.fire(event);
|
|
5839
|
-
}), addDisposableListener(this._element, 'dragstart', (event) => {
|
|
5840
|
-
this._onDragStart.fire(event);
|
|
5841
6815
|
}));
|
|
5842
6816
|
}
|
|
5843
6817
|
init(params) {
|
|
@@ -6119,7 +7093,7 @@
|
|
|
6119
7093
|
let svg = underline.firstElementChild;
|
|
6120
7094
|
let path;
|
|
6121
7095
|
if (!svg || svg.tagName !== 'svg') {
|
|
6122
|
-
underline.
|
|
7096
|
+
underline.replaceChildren();
|
|
6123
7097
|
svg = document.createElementNS('http://www.w3.org/2000/svg', 'svg');
|
|
6124
7098
|
svg.style.display = 'block';
|
|
6125
7099
|
path = document.createElementNS('http://www.w3.org/2000/svg', 'path');
|
|
@@ -6217,7 +7191,7 @@
|
|
|
6217
7191
|
underline.style.display = '';
|
|
6218
7192
|
// Clear any SVG content left over from a mode switch
|
|
6219
7193
|
if (underline.firstElementChild) {
|
|
6220
|
-
underline.
|
|
7194
|
+
underline.replaceChildren();
|
|
6221
7195
|
}
|
|
6222
7196
|
underline.style.backgroundColor = color;
|
|
6223
7197
|
if (isVertical) {
|
|
@@ -6301,6 +7275,12 @@
|
|
|
6301
7275
|
this._positionChipForGroup(tabGroup);
|
|
6302
7276
|
}
|
|
6303
7277
|
}
|
|
7278
|
+
updateDirection() {
|
|
7279
|
+
const isVertical = this._ctx.getDirection() === 'vertical';
|
|
7280
|
+
for (const [, entry] of this._chipRenderers) {
|
|
7281
|
+
entry.dropTarget.setTargetZones(isVertical ? ['top'] : ['left']);
|
|
7282
|
+
}
|
|
7283
|
+
}
|
|
6304
7284
|
snapshotChipWidths() {
|
|
6305
7285
|
const widths = new Map();
|
|
6306
7286
|
for (const [groupId, entry] of this._chipRenderers) {
|
|
@@ -6394,6 +7374,45 @@
|
|
|
6394
7374
|
(_a = this._pendingTransitionCleanups.get(panelId)) === null || _a === void 0 ? void 0 : _a();
|
|
6395
7375
|
this._pendingTransitionCleanups.delete(panelId);
|
|
6396
7376
|
}
|
|
7377
|
+
updateDragAndDropState() {
|
|
7378
|
+
const caps = resolveDndCapabilities(this._ctx.accessor.options);
|
|
7379
|
+
for (const entry of this._chipRenderers.values()) {
|
|
7380
|
+
entry.chip.element.draggable = caps.html5;
|
|
7381
|
+
entry.html5DragSource.setDisabled(!caps.html5);
|
|
7382
|
+
entry.pointerDragSource.setDisabled(!caps.pointer);
|
|
7383
|
+
entry.pointerDragSource.setTouchOnly(!caps.pointerHandlesMouse);
|
|
7384
|
+
}
|
|
7385
|
+
}
|
|
7386
|
+
/**
|
|
7387
|
+
* Synchronously dispose the chip drag sources for an in-flight chip
|
|
7388
|
+
* drag. Called from `_commitGroupMove` so the transfer payload +
|
|
7389
|
+
* iframe shield are released BEFORE the cross-group move detaches
|
|
7390
|
+
* the chip (chip dispose is scheduled on a microtask via
|
|
7391
|
+
* `_scheduleTabGroupUpdate`, which is too late for callers that read
|
|
7392
|
+
* `getPanelData()` synchronously after the move). Idempotent — the
|
|
7393
|
+
* subsequent `update()` will also dispose the sources.
|
|
7394
|
+
*/
|
|
7395
|
+
disposeChipDrag(tabGroupId) {
|
|
7396
|
+
var _a, _b;
|
|
7397
|
+
const entry = this._chipRenderers.get(tabGroupId);
|
|
7398
|
+
if (!entry) {
|
|
7399
|
+
return;
|
|
7400
|
+
}
|
|
7401
|
+
// Optional-chained because tests may inject minimal entries
|
|
7402
|
+
// that skip the manager's normal `_ensureChipForGroup` flow.
|
|
7403
|
+
(_a = entry.html5DragSource) === null || _a === void 0 ? void 0 : _a.dispose();
|
|
7404
|
+
(_b = entry.pointerDragSource) === null || _b === void 0 ? void 0 : _b.dispose();
|
|
7405
|
+
}
|
|
7406
|
+
/** Cloned chip rect used as the pointer follow-finger ghost. */
|
|
7407
|
+
_buildChipGhostElement(chipEl) {
|
|
7408
|
+
const style = getComputedStyle(chipEl);
|
|
7409
|
+
const clone = chipEl.cloneNode(true);
|
|
7410
|
+
Array.from(style).forEach((key) => {
|
|
7411
|
+
clone.style.setProperty(key, style.getPropertyValue(key), style.getPropertyPriority(key));
|
|
7412
|
+
});
|
|
7413
|
+
clone.style.position = 'absolute';
|
|
7414
|
+
return clone;
|
|
7415
|
+
}
|
|
6397
7416
|
disposeAll() {
|
|
6398
7417
|
var _a;
|
|
6399
7418
|
(_a = this._indicator) === null || _a === void 0 ? void 0 : _a.dispose();
|
|
@@ -6439,6 +7458,74 @@
|
|
|
6439
7458
|
? createChip(tabGroup)
|
|
6440
7459
|
: new TabGroupChip(this._ctx.accessor.tabGroupColorPalette);
|
|
6441
7460
|
chip.init({ tabGroup, api: this._ctx.accessor.api });
|
|
7461
|
+
const caps = resolveDndCapabilities(this._ctx.accessor.options);
|
|
7462
|
+
chip.element.draggable = caps.html5;
|
|
7463
|
+
const panelTransfer = LocalSelectionTransfer.getInstance();
|
|
7464
|
+
// Shared `getData` for both backends. Sets a group-level
|
|
7465
|
+
// PanelTransfer (panelId=null, tabGroupId identifies the group).
|
|
7466
|
+
// The returned disposer clears it on drag end.
|
|
7467
|
+
const getData = () => {
|
|
7468
|
+
panelTransfer.setData([
|
|
7469
|
+
new PanelTransfer(this._ctx.accessor.id, this._ctx.group.id, null, tabGroup.id),
|
|
7470
|
+
], PanelTransfer.prototype);
|
|
7471
|
+
return {
|
|
7472
|
+
dispose: () => {
|
|
7473
|
+
panelTransfer.clearData(PanelTransfer.prototype);
|
|
7474
|
+
},
|
|
7475
|
+
};
|
|
7476
|
+
};
|
|
7477
|
+
// The chip's HTML5 drag image is the cloned tabs list (chip only),
|
|
7478
|
+
// mounted inside the dockview root for CSS-variable inheritance and
|
|
7479
|
+
// positioned against the chip's in-place rect. Layout-dependent
|
|
7480
|
+
// offset means we set the drag image directly in `onDragStart`
|
|
7481
|
+
// (inside the dragstart handler) rather than via the generic
|
|
7482
|
+
// `createGhost` factory, which only knows about ghost specs that
|
|
7483
|
+
// can be appended to `document.body`.
|
|
7484
|
+
const html5DragSource = html5Backend.createDragSource(chip.element, {
|
|
7485
|
+
getData,
|
|
7486
|
+
disabled: !caps.html5,
|
|
7487
|
+
isCancelled: () => !resolveDndCapabilities(this._ctx.accessor.options).html5,
|
|
7488
|
+
onDragStart: (event) => {
|
|
7489
|
+
// Type guard via `dataTransfer` — `instanceof DragEvent`
|
|
7490
|
+
// would throw in jsdom which doesn't ship a DragEvent
|
|
7491
|
+
// constructor.
|
|
7492
|
+
if ('dataTransfer' in event && event.dataTransfer) {
|
|
7493
|
+
this.setGroupDragImage(event, tabGroup, chip.element);
|
|
7494
|
+
}
|
|
7495
|
+
this._callbacks.onChipDragStart(tabGroup, chip, event);
|
|
7496
|
+
},
|
|
7497
|
+
onDragEnd: (event) => {
|
|
7498
|
+
var _a, _b;
|
|
7499
|
+
(_b = (_a = this._callbacks).onChipDragEnd) === null || _b === void 0 ? void 0 : _b.call(_a, tabGroup, chip, event);
|
|
7500
|
+
},
|
|
7501
|
+
});
|
|
7502
|
+
// Synchronous panelTransfer cleanup directly on the chip element.
|
|
7503
|
+
// `Html5DragSource`'s dragend defers data disposal via `setTimeout(0)`
|
|
7504
|
+
// so drop handlers can read the payload — but a chip drag that
|
|
7505
|
+
// ends via `moveGroupOrPanel` (no actual drop event) needs the
|
|
7506
|
+
// singleton cleared immediately, otherwise a synchronous
|
|
7507
|
+
// `getPanelData()` after the move still sees the stale chip
|
|
7508
|
+
// payload. Attached directly (not via `addDisposableListener`) so
|
|
7509
|
+
// the listener survives chip disposal in the detach-then-dragend
|
|
7510
|
+
// cross-group path; `once: true` auto-removes after the single
|
|
7511
|
+
// dragend that we care about. (#1254)
|
|
7512
|
+
chip.element.addEventListener('dragend', () => {
|
|
7513
|
+
panelTransfer.clearData(PanelTransfer.prototype);
|
|
7514
|
+
}, { once: true });
|
|
7515
|
+
const pointerDragSource = pointerBackend.createDragSource(chip.element, {
|
|
7516
|
+
getData,
|
|
7517
|
+
disabled: !caps.pointer,
|
|
7518
|
+
touchOnly: !caps.pointerHandlesMouse,
|
|
7519
|
+
isCancelled: () => !resolveDndCapabilities(this._ctx.accessor.options).pointer,
|
|
7520
|
+
createGhost: () => ({
|
|
7521
|
+
element: this._buildChipGhostElement(chip.element),
|
|
7522
|
+
offsetX: 8,
|
|
7523
|
+
offsetY: 8,
|
|
7524
|
+
}),
|
|
7525
|
+
onDragStart: (event) => {
|
|
7526
|
+
this._callbacks.onChipDragStart(tabGroup, chip, event);
|
|
7527
|
+
},
|
|
7528
|
+
});
|
|
6442
7529
|
const disposables = [
|
|
6443
7530
|
tabGroup.onDidChange(() => {
|
|
6444
7531
|
var _a;
|
|
@@ -6452,24 +7539,70 @@
|
|
|
6452
7539
|
tabGroup.onDidCollapseChange(() => {
|
|
6453
7540
|
this._updateTabGroupClasses();
|
|
6454
7541
|
}),
|
|
7542
|
+
html5DragSource,
|
|
7543
|
+
pointerDragSource,
|
|
6455
7544
|
];
|
|
6456
|
-
//
|
|
7545
|
+
// Context menu: built-in TabGroupChip already aggregates right-click
|
|
7546
|
+
// + touch long-press into `onContextMenu`. Custom chip renderers
|
|
7547
|
+
// don't, so attach a long-press detector and contextmenu listener
|
|
7548
|
+
// directly on their element.
|
|
7549
|
+
const onContextMenu = (event) => {
|
|
7550
|
+
// A long-press on a chip should preempt the in-flight pointer
|
|
7551
|
+
// drag and open the menu instead.
|
|
7552
|
+
pointerDragSource.cancelPending();
|
|
7553
|
+
this._callbacks.onChipContextMenu(tabGroup, event);
|
|
7554
|
+
};
|
|
6457
7555
|
if (chip instanceof TabGroupChip) {
|
|
6458
|
-
disposables.push(chip.onContextMenu(
|
|
6459
|
-
this._callbacks.onChipContextMenu(tabGroup, event);
|
|
6460
|
-
}), chip.onDragStart((event) => {
|
|
6461
|
-
this._callbacks.onChipDragStart(tabGroup, chip, event);
|
|
6462
|
-
}));
|
|
7556
|
+
disposables.push(chip.onContextMenu(onContextMenu));
|
|
6463
7557
|
}
|
|
6464
7558
|
else {
|
|
6465
|
-
disposables.push(
|
|
6466
|
-
|
|
6467
|
-
}), addDisposableListener(chip.element, '
|
|
6468
|
-
|
|
6469
|
-
|
|
6470
|
-
|
|
7559
|
+
disposables.push(new LongPressDetector(chip.element, {
|
|
7560
|
+
onLongPress: onContextMenu,
|
|
7561
|
+
}), addDisposableListener(chip.element, 'contextmenu', onContextMenu));
|
|
7562
|
+
}
|
|
7563
|
+
// The chip sits before its group's first tab in the DOM, so it
|
|
7564
|
+
// covers the "drop before the group" position. Without a drop
|
|
7565
|
+
// target here, dropping a tab over the chip is a dead zone —
|
|
7566
|
+
// particularly visible when the group is first in the tabs list
|
|
7567
|
+
// and there's no preceding tab whose right zone covers position 0.
|
|
7568
|
+
// The smooth animation path already shifts the chip's margin to
|
|
7569
|
+
// open a gap, so suppress the overlay in that mode.
|
|
7570
|
+
const isVertical = this._ctx.getDirection() === 'vertical';
|
|
7571
|
+
const dropTarget = new Droptarget(chip.element, {
|
|
7572
|
+
acceptedTargetZones: isVertical ? ['top'] : ['left'],
|
|
7573
|
+
overlayModel: {
|
|
7574
|
+
activationSize: { value: 100, type: 'percentage' },
|
|
7575
|
+
},
|
|
7576
|
+
canDisplayOverlay: (event, position) => {
|
|
7577
|
+
var _a;
|
|
7578
|
+
if (this._ctx.group.locked) {
|
|
7579
|
+
return false;
|
|
7580
|
+
}
|
|
7581
|
+
if (this._ctx.accessor.options.disableDnd) {
|
|
7582
|
+
return false;
|
|
7583
|
+
}
|
|
7584
|
+
const data = getPanelData();
|
|
7585
|
+
if (data && this._ctx.accessor.id === data.viewId) {
|
|
7586
|
+
if (((_a = this._ctx.accessor.options.theme) === null || _a === void 0 ? void 0 : _a.tabAnimation) ===
|
|
7587
|
+
'smooth') {
|
|
7588
|
+
return false;
|
|
7589
|
+
}
|
|
7590
|
+
return true;
|
|
7591
|
+
}
|
|
7592
|
+
return this._ctx.group.model.canDisplayOverlay(event, position, 'tab');
|
|
7593
|
+
},
|
|
7594
|
+
});
|
|
7595
|
+
disposables.push(dropTarget, dropTarget.onDrop((event) => {
|
|
7596
|
+
this._callbacks.onChipDrop(tabGroup, event);
|
|
7597
|
+
}));
|
|
6471
7598
|
const disposable = new CompositeDisposable(...disposables);
|
|
6472
|
-
this._chipRenderers.set(tabGroup.id, {
|
|
7599
|
+
this._chipRenderers.set(tabGroup.id, {
|
|
7600
|
+
chip,
|
|
7601
|
+
html5DragSource,
|
|
7602
|
+
pointerDragSource,
|
|
7603
|
+
disposable,
|
|
7604
|
+
dropTarget,
|
|
7605
|
+
});
|
|
6473
7606
|
// Group is born collapsed (cross-group drop, layout restore, etc.):
|
|
6474
7607
|
// its tabs are about to be added without the collapsed class. Skip
|
|
6475
7608
|
// the animation in the upcoming _updateTabGroupClasses call so they
|
|
@@ -6728,6 +7861,7 @@
|
|
|
6728
7861
|
for (const tab of this._tabs) {
|
|
6729
7862
|
tab.value.setDirection(value);
|
|
6730
7863
|
}
|
|
7864
|
+
this._tabGroupManager.updateDirection();
|
|
6731
7865
|
}
|
|
6732
7866
|
constructor(group, accessor, options) {
|
|
6733
7867
|
super();
|
|
@@ -6747,7 +7881,7 @@
|
|
|
6747
7881
|
this._voidContainer = null;
|
|
6748
7882
|
this._voidContainerListeners = null;
|
|
6749
7883
|
this._extendedDropZone = null;
|
|
6750
|
-
this.
|
|
7884
|
+
this._pointerInsideTabsList = false;
|
|
6751
7885
|
this._onTabDragStart = new Emitter();
|
|
6752
7886
|
this.onTabDragStart = this._onTabDragStart.event;
|
|
6753
7887
|
this._onDrop = new Emitter();
|
|
@@ -6782,13 +7916,40 @@
|
|
|
6782
7916
|
onChipDragStart: (tabGroup, chip, event) => {
|
|
6783
7917
|
this._handleChipDragStart(tabGroup, chip, event);
|
|
6784
7918
|
},
|
|
7919
|
+
onChipDragEnd: () => {
|
|
7920
|
+
// HTML5 chip dragend (incl. cancels). The Html5DragSource
|
|
7921
|
+
// owns the listener on the chip element, so this fires
|
|
7922
|
+
// even if the chip was detached cross-group — the
|
|
7923
|
+
// element keeps its listeners until the source is
|
|
7924
|
+
// disposed. resetDragAnimation is a no-op after a
|
|
7925
|
+
// successful drop (anim state already null) thanks to
|
|
7926
|
+
// the gating inside it.
|
|
7927
|
+
this.resetDragAnimation();
|
|
7928
|
+
},
|
|
7929
|
+
onChipDrop: (tabGroup, event) => {
|
|
7930
|
+
this._handleChipDrop(tabGroup, event);
|
|
7931
|
+
},
|
|
6785
7932
|
});
|
|
6786
7933
|
this.addDisposables(this._onOverflowTabsChange, this._observerDisposable, this._onWillShowOverlay, this._onDrop, this._onTabDragStart, {
|
|
6787
7934
|
dispose: () => {
|
|
6788
7935
|
var _a;
|
|
6789
7936
|
(_a = this._flipTransitionCleanup) === null || _a === void 0 ? void 0 : _a.call(this);
|
|
6790
7937
|
},
|
|
6791
|
-
},
|
|
7938
|
+
},
|
|
7939
|
+
// Pointer-side cleanup: when any pointer drag ends, tear
|
|
7940
|
+
// down smooth-reorder anim state the dragover bridge may
|
|
7941
|
+
// have installed. The chip's pointer drag source handles
|
|
7942
|
+
// its own transfer payload + iframe-shield cleanup.
|
|
7943
|
+
PointerDragController.getInstance().onDragEnd(() => {
|
|
7944
|
+
this._pointerInsideTabsList = false;
|
|
7945
|
+
this.resetDragAnimation();
|
|
7946
|
+
}),
|
|
7947
|
+
// Pointer-event mirror of the HTML5 dragover / dragleave handlers
|
|
7948
|
+
// below. Drives smooth-reorder for `dndStrategy: 'pointer'` and
|
|
7949
|
+
// for touch drags in `'auto'`.
|
|
7950
|
+
PointerDragController.getInstance().onDragMove((e) => {
|
|
7951
|
+
this._handlePointerDragMove(e.clientX, e.clientY);
|
|
7952
|
+
}), addDisposableListener(this.element, 'pointerdown', (event) => {
|
|
6792
7953
|
if (event.defaultPrevented) {
|
|
6793
7954
|
return;
|
|
6794
7955
|
}
|
|
@@ -6796,135 +7957,60 @@
|
|
|
6796
7957
|
if (isLeftClick) {
|
|
6797
7958
|
this.accessor.doSetGroupActive(this.group);
|
|
6798
7959
|
}
|
|
6799
|
-
}),
|
|
6800
|
-
|
|
6801
|
-
|
|
6802
|
-
|
|
6803
|
-
|
|
6804
|
-
|
|
6805
|
-
|
|
6806
|
-
|
|
6807
|
-
|
|
6808
|
-
|
|
6809
|
-
|
|
6810
|
-
|
|
6811
|
-
|
|
6812
|
-
|
|
6813
|
-
|
|
6814
|
-
|
|
6815
|
-
if (!this._animState) {
|
|
6816
|
-
const data = getPanelData();
|
|
6817
|
-
// In default animation mode, individual tab drops
|
|
6818
|
-
// are handled by per-tab Droptargets. But tab group
|
|
6819
|
-
// chip drags still need tab-list-level handling so
|
|
6820
|
-
// that drops on gaps / void space work.
|
|
6821
|
-
if (((_a = this.accessor.options.theme) === null || _a === void 0 ? void 0 : _a.tabAnimation) ===
|
|
6822
|
-
'default' &&
|
|
6823
|
-
!(data === null || data === void 0 ? void 0 : data.tabGroupId)) {
|
|
6824
|
-
return;
|
|
6825
|
-
}
|
|
6826
|
-
if (data &&
|
|
6827
|
-
(data.panelId || data.tabGroupId) &&
|
|
6828
|
-
data.groupId !== this.group.id) {
|
|
6829
|
-
const avgWidth = this.getAverageTabWidth();
|
|
6830
|
-
if (data.tabGroupId) {
|
|
6831
|
-
// External group drag — look up the
|
|
6832
|
-
// source tab group to size the gap
|
|
6833
|
-
const sourceGroup = this.accessor.getPanel(data.groupId);
|
|
6834
|
-
const sourceTg = sourceGroup === null || sourceGroup === void 0 ? void 0 : sourceGroup.model.getTabGroups().find((tg) => tg.id === data.tabGroupId);
|
|
6835
|
-
const panelCount = (_b = sourceTg === null || sourceTg === void 0 ? void 0 : sourceTg.panelIds.length) !== null && _b !== void 0 ? _b : 1;
|
|
6836
|
-
const groupGapWidth = avgWidth * panelCount + avgWidth;
|
|
6837
|
-
this._animState = {
|
|
6838
|
-
sourceTabId: '',
|
|
6839
|
-
sourceIndex: -1,
|
|
6840
|
-
tabPositions: this.snapshotTabPositions(),
|
|
6841
|
-
chipPositions: this._tabGroupManager.snapshotChipWidths(),
|
|
6842
|
-
currentInsertionIndex: null,
|
|
6843
|
-
targetTabGroupId: null,
|
|
6844
|
-
sourceTabGroupId: data.tabGroupId,
|
|
6845
|
-
sourceGroupPanelIds: sourceTg
|
|
6846
|
-
? new Set(sourceTg.panelIds)
|
|
6847
|
-
: new Set(),
|
|
6848
|
-
sourceChipWidth: avgWidth,
|
|
6849
|
-
cursorOffsetFromDragLeft: groupGapWidth / 2,
|
|
6850
|
-
sourceGapWidth: groupGapWidth,
|
|
6851
|
-
containerLeft: this._tabsList.getBoundingClientRect()
|
|
6852
|
-
.left,
|
|
6853
|
-
};
|
|
6854
|
-
}
|
|
6855
|
-
else {
|
|
6856
|
-
this._animState = {
|
|
6857
|
-
sourceTabId: data.panelId,
|
|
6858
|
-
sourceIndex: -1,
|
|
6859
|
-
tabPositions: this.snapshotTabPositions(),
|
|
6860
|
-
chipPositions: this._tabGroupManager.snapshotChipWidths(),
|
|
6861
|
-
currentInsertionIndex: null,
|
|
6862
|
-
targetTabGroupId: null,
|
|
6863
|
-
sourceTabGroupId: null,
|
|
6864
|
-
sourceGroupPanelIds: null,
|
|
6865
|
-
sourceChipWidth: 0,
|
|
6866
|
-
cursorOffsetFromDragLeft: avgWidth / 2,
|
|
6867
|
-
sourceGapWidth: avgWidth,
|
|
6868
|
-
containerLeft: this._tabsList.getBoundingClientRect()
|
|
6869
|
-
.left,
|
|
6870
|
-
};
|
|
6871
|
-
}
|
|
6872
|
-
}
|
|
6873
|
-
else {
|
|
6874
|
-
return;
|
|
6875
|
-
}
|
|
6876
|
-
}
|
|
6877
|
-
event.preventDefault(); // allow drop to fire on the container
|
|
6878
|
-
// For intra-group drag (sourceIndex >= 0) the gap
|
|
6879
|
-
// animation is the sole visual indicator — clear any
|
|
6880
|
-
// stale anchor overlay that may have been set while the
|
|
6881
|
-
// cursor was over the panel content area or another zone.
|
|
6882
|
-
// External drags (sourceIndex === -1) leave the overlay
|
|
6883
|
-
// to the individual tab Droptargets so cross-group
|
|
6884
|
-
// animation is not disrupted.
|
|
6885
|
-
if (this._animState.sourceIndex !== -1) {
|
|
6886
|
-
(_d = (_c = this.group.model.dropTargetContainer) === null || _c === void 0 ? void 0 : _c.model) === null || _d === void 0 ? void 0 : _d.clear();
|
|
6887
|
-
}
|
|
6888
|
-
this.handleDragOver(event);
|
|
6889
|
-
}, true), addDisposableListener(this._tabsList, 'dragleave', (event) => {
|
|
6890
|
-
var _a, _b, _c;
|
|
6891
|
-
if (!this._animState) {
|
|
7960
|
+
}),
|
|
7961
|
+
// Trackpad / wheel forwarding. The strip scrolls along its own
|
|
7962
|
+
// axis (x for horizontal headers, y for vertical), so deltaY
|
|
7963
|
+
// from a plain mouse wheel maps onto the strip's axis too —
|
|
7964
|
+
// this gives the VS Code-style "scroll over tab bar to page
|
|
7965
|
+
// through tabs" feel. We only consume the event when the strip
|
|
7966
|
+
// is actually overflowing in the direction the user wheeled in,
|
|
7967
|
+
// so a wheel at the edge of a non-overflowing strip still
|
|
7968
|
+
// bubbles up and scrolls the page. `{ passive: false }` is
|
|
7969
|
+
// required because we call preventDefault().
|
|
7970
|
+
addDisposableListener(this._tabsList, 'wheel', (event) => {
|
|
7971
|
+
const isVertical = this._direction === 'vertical';
|
|
7972
|
+
const primary = isVertical
|
|
7973
|
+
? event.deltaY || event.deltaX
|
|
7974
|
+
: event.deltaX || event.deltaY;
|
|
7975
|
+
if (primary === 0) {
|
|
6892
7976
|
return;
|
|
6893
7977
|
}
|
|
6894
|
-
const
|
|
6895
|
-
|
|
6896
|
-
|
|
6897
|
-
|
|
6898
|
-
|
|
6899
|
-
|
|
6900
|
-
// left actions), keep _animState alive so the external
|
|
6901
|
-
// dragover listeners can continue the gap animation.
|
|
6902
|
-
if (related && ((_a = this._extendedDropZone) === null || _a === void 0 ? void 0 : _a.contains(related))) {
|
|
6903
|
-
this.resetTabTransforms();
|
|
6904
|
-
this._animState.currentInsertionIndex = null;
|
|
7978
|
+
const max = isVertical
|
|
7979
|
+
? this._tabsList.scrollHeight -
|
|
7980
|
+
this._tabsList.clientHeight
|
|
7981
|
+
: this._tabsList.scrollWidth -
|
|
7982
|
+
this._tabsList.clientWidth;
|
|
7983
|
+
if (max <= 0) {
|
|
6905
7984
|
return;
|
|
6906
7985
|
}
|
|
6907
|
-
|
|
6908
|
-
|
|
6909
|
-
|
|
6910
|
-
|
|
6911
|
-
|
|
6912
|
-
|
|
6913
|
-
(
|
|
6914
|
-
this._voidContainer.contains(rt));
|
|
6915
|
-
if (isVoid) {
|
|
7986
|
+
const current = isVertical
|
|
7987
|
+
? this._tabsList.scrollTop
|
|
7988
|
+
: this._tabsList.scrollLeft;
|
|
7989
|
+
// At the edge in the wheel direction: let the page
|
|
7990
|
+
// scroll instead of trapping the gesture.
|
|
7991
|
+
if ((primary < 0 && current <= 0) ||
|
|
7992
|
+
(primary > 0 && current >= max)) {
|
|
6916
7993
|
return;
|
|
6917
7994
|
}
|
|
6918
|
-
|
|
6919
|
-
|
|
6920
|
-
|
|
6921
|
-
|
|
6922
|
-
|
|
6923
|
-
|
|
6924
|
-
|
|
6925
|
-
|
|
6926
|
-
|
|
7995
|
+
event.preventDefault();
|
|
7996
|
+
// Custom-scrollbar mode wraps the tabs list and installs
|
|
7997
|
+
// its own wheel listener that rewrites scrollLeft from a
|
|
7998
|
+
// deltaY-only tracker. Without stopPropagation that
|
|
7999
|
+
// handler would clobber our deltaX-aware update.
|
|
8000
|
+
event.stopPropagation();
|
|
8001
|
+
if (isVertical) {
|
|
8002
|
+
this._tabsList.scrollTop = current + primary;
|
|
8003
|
+
}
|
|
8004
|
+
else {
|
|
8005
|
+
this._tabsList.scrollLeft = current + primary;
|
|
8006
|
+
}
|
|
8007
|
+
}, { passive: false }), addDisposableListener(this._tabsList, 'dragover', (event) => {
|
|
8008
|
+
if (this._processDragOver(event.clientX)) {
|
|
8009
|
+
// Allow `drop` to fire on the tabs list container.
|
|
8010
|
+
event.preventDefault();
|
|
6927
8011
|
}
|
|
8012
|
+
}, true), addDisposableListener(this._tabsList, 'dragleave', (event) => {
|
|
8013
|
+
this._processDragLeave(event.relatedTarget);
|
|
6928
8014
|
}, true), addDisposableListener(this._tabsList, 'dragend', () => {
|
|
6929
8015
|
this.resetDragAnimation();
|
|
6930
8016
|
}), addDisposableListener(this._tabsList, 'drop', (event) => {
|
|
@@ -7046,6 +8132,9 @@
|
|
|
7046
8132
|
const disposable = new CompositeDisposable(tab.onDragStart((event) => {
|
|
7047
8133
|
var _a;
|
|
7048
8134
|
this._onTabDragStart.fire({ nativeEvent: event, panel });
|
|
8135
|
+
// Both HTML5 and pointer drags initialize _animState. Cleanup
|
|
8136
|
+
// is wired in both paths: HTML5 via dragend/drop on _tabsList,
|
|
8137
|
+
// pointer via PointerDragController.onDragEnd subscriptions.
|
|
7049
8138
|
if (((_a = this.accessor.options.theme) === null || _a === void 0 ? void 0 : _a.tabAnimation) === 'smooth') {
|
|
7050
8139
|
const tabWidth = tab.element.getBoundingClientRect().width;
|
|
7051
8140
|
const sourceIndex = this._tabs.findIndex((x) => x.value === tab);
|
|
@@ -7305,6 +8394,7 @@
|
|
|
7305
8394
|
for (const tab of this._tabs) {
|
|
7306
8395
|
tab.value.updateDragAndDropState();
|
|
7307
8396
|
}
|
|
8397
|
+
this._tabGroupManager.updateDragAndDropState();
|
|
7308
8398
|
}
|
|
7309
8399
|
/**
|
|
7310
8400
|
* Synchronize chip elements and CSS classes for all tab groups
|
|
@@ -7316,6 +8406,13 @@
|
|
|
7316
8406
|
refreshTabGroupAccent() {
|
|
7317
8407
|
this._tabGroupManager.refreshAccents();
|
|
7318
8408
|
}
|
|
8409
|
+
/**
|
|
8410
|
+
* Tabs-list-specific side effects of a chip drag start. The chip's
|
|
8411
|
+
* drag sources (constructed by `TabGroupManager`) own the transfer
|
|
8412
|
+
* payload, iframe shielding, dataTransfer setup, and the HTML5 drag
|
|
8413
|
+
* image. This method just sets up the smooth-reorder anim state and
|
|
8414
|
+
* collapses the source-group tabs in the tabs list.
|
|
8415
|
+
*/
|
|
7319
8416
|
_handleChipDragStart(tabGroup, chip, event) {
|
|
7320
8417
|
var _a;
|
|
7321
8418
|
const firstPanelId = tabGroup.panelIds[0];
|
|
@@ -7346,89 +8443,79 @@
|
|
|
7346
8443
|
sourceGapWidth: groupGapWidth,
|
|
7347
8444
|
containerLeft: this._tabsList.getBoundingClientRect().left,
|
|
7348
8445
|
};
|
|
7349
|
-
|
|
7350
|
-
|
|
7351
|
-
|
|
7352
|
-
|
|
7353
|
-
|
|
7354
|
-
|
|
7355
|
-
|
|
7356
|
-
|
|
7357
|
-
|
|
7358
|
-
|
|
7359
|
-
|
|
7360
|
-
|
|
7361
|
-
|
|
7362
|
-
|
|
7363
|
-
|
|
7364
|
-
|
|
7365
|
-
|
|
7366
|
-
|
|
7367
|
-
|
|
7368
|
-
|
|
7369
|
-
};
|
|
7370
|
-
chipElement.addEventListener('dragend', onChipDragEnd);
|
|
7371
|
-
this._chipDragCleanup = {
|
|
7372
|
-
dispose: () => {
|
|
7373
|
-
chipElement.removeEventListener('dragend', onChipDragEnd);
|
|
7374
|
-
panelTransfer.clearData(PanelTransfer.prototype);
|
|
7375
|
-
iframes.release();
|
|
7376
|
-
},
|
|
7377
|
-
};
|
|
7378
|
-
if (event.dataTransfer) {
|
|
7379
|
-
event.dataTransfer.effectAllowed = 'move';
|
|
7380
|
-
if (event.dataTransfer.items.length === 0) {
|
|
7381
|
-
event.dataTransfer.setData('text/plain', '');
|
|
7382
|
-
}
|
|
7383
|
-
}
|
|
7384
|
-
if (((_a = this.accessor.options.theme) === null || _a === void 0 ? void 0 : _a.tabAnimation) === 'smooth') {
|
|
7385
|
-
// Collapse group tabs + chip after the browser
|
|
7386
|
-
// captures the drag image, then open the gap at the
|
|
7387
|
-
// source position — all instant (no transitions).
|
|
7388
|
-
const groupPanelIds = new Set(tabGroup.panelIds);
|
|
7389
|
-
this._pendingCollapse = true;
|
|
7390
|
-
requestAnimationFrame(() => {
|
|
7391
|
-
var _a;
|
|
7392
|
-
var _b;
|
|
7393
|
-
this._pendingCollapse = false;
|
|
7394
|
-
if (!this._animState) {
|
|
7395
|
-
return;
|
|
7396
|
-
}
|
|
7397
|
-
// Collapse all group tabs instantly
|
|
7398
|
-
for (const t of this._tabs) {
|
|
7399
|
-
if (groupPanelIds.has(t.value.panel.id)) {
|
|
7400
|
-
t.value.element.style.transition = 'none';
|
|
7401
|
-
toggleClass(t.value.element, 'dv-tab--dragging', true);
|
|
7402
|
-
}
|
|
7403
|
-
}
|
|
7404
|
-
// Collapse the group chip instantly
|
|
7405
|
-
const chipEntry = this._tabGroupManager.chipRenderers.get(tabGroup.id);
|
|
7406
|
-
if (chipEntry) {
|
|
7407
|
-
chipEntry.chip.element.style.transition = 'none';
|
|
7408
|
-
toggleClass(chipEntry.chip.element, 'dv-tab-group-chip--dragging', true);
|
|
7409
|
-
}
|
|
7410
|
-
// Single reflow for the entire batch
|
|
7411
|
-
void this._tabsList.offsetHeight;
|
|
7412
|
-
const underline = this._tabGroupManager.groupUnderlines.get(tabGroup.id);
|
|
7413
|
-
if (underline) {
|
|
7414
|
-
underline.style.display = 'none';
|
|
7415
|
-
}
|
|
7416
|
-
(_a = (_b = this._animState).currentInsertionIndex) !== null && _a !== void 0 ? _a : (_b.currentInsertionIndex = firstIdx);
|
|
7417
|
-
// Apply gap with transitions disabled
|
|
7418
|
-
this.applyDragOverTransforms(true);
|
|
7419
|
-
// Re-enable transitions for subsequent moves
|
|
7420
|
-
for (const t of this._tabs) {
|
|
7421
|
-
if (groupPanelIds.has(t.value.panel.id)) {
|
|
7422
|
-
t.value.element.style.removeProperty('transition');
|
|
7423
|
-
}
|
|
8446
|
+
if (((_a = this.accessor.options.theme) === null || _a === void 0 ? void 0 : _a.tabAnimation) !== 'smooth') {
|
|
8447
|
+
return;
|
|
8448
|
+
}
|
|
8449
|
+
// Collapse group tabs + chip after the browser captures the drag
|
|
8450
|
+
// image, then open the gap at the source position — all instant
|
|
8451
|
+
// (no transitions).
|
|
8452
|
+
const groupPanelIds = new Set(tabGroup.panelIds);
|
|
8453
|
+
this._pendingCollapse = true;
|
|
8454
|
+
requestAnimationFrame(() => {
|
|
8455
|
+
var _a;
|
|
8456
|
+
var _b;
|
|
8457
|
+
this._pendingCollapse = false;
|
|
8458
|
+
if (!this._animState) {
|
|
8459
|
+
return;
|
|
8460
|
+
}
|
|
8461
|
+
// Collapse all group tabs instantly
|
|
8462
|
+
for (const t of this._tabs) {
|
|
8463
|
+
if (groupPanelIds.has(t.value.panel.id)) {
|
|
8464
|
+
t.value.element.style.transition = 'none';
|
|
8465
|
+
toggleClass(t.value.element, 'dv-tab--dragging', true);
|
|
7424
8466
|
}
|
|
7425
|
-
|
|
7426
|
-
|
|
8467
|
+
}
|
|
8468
|
+
// Collapse the group chip instantly
|
|
8469
|
+
const chipEntry = this._tabGroupManager.chipRenderers.get(tabGroup.id);
|
|
8470
|
+
if (chipEntry) {
|
|
8471
|
+
chipEntry.chip.element.style.transition = 'none';
|
|
8472
|
+
toggleClass(chipEntry.chip.element, 'dv-tab-group-chip--dragging', true);
|
|
8473
|
+
}
|
|
8474
|
+
// Single reflow for the entire batch
|
|
8475
|
+
void this._tabsList.offsetHeight;
|
|
8476
|
+
const underline = this._tabGroupManager.groupUnderlines.get(tabGroup.id);
|
|
8477
|
+
if (underline) {
|
|
8478
|
+
underline.style.display = 'none';
|
|
8479
|
+
}
|
|
8480
|
+
(_a = (_b = this._animState).currentInsertionIndex) !== null && _a !== void 0 ? _a : (_b.currentInsertionIndex = firstIdx);
|
|
8481
|
+
this.applyDragOverTransforms(true);
|
|
8482
|
+
for (const t of this._tabs) {
|
|
8483
|
+
if (groupPanelIds.has(t.value.panel.id)) {
|
|
8484
|
+
t.value.element.style.removeProperty('transition');
|
|
7427
8485
|
}
|
|
7428
|
-
}
|
|
8486
|
+
}
|
|
8487
|
+
if (chipEntry) {
|
|
8488
|
+
chipEntry.chip.element.style.removeProperty('transition');
|
|
8489
|
+
}
|
|
8490
|
+
});
|
|
8491
|
+
}
|
|
8492
|
+
/**
|
|
8493
|
+
* A drop on a tab group chip means "insert before this group". Resolve to
|
|
8494
|
+
* the index of the group's first tab, adjusting for same-group removal
|
|
8495
|
+
* (when the source tab is currently to the left of the target slot, its
|
|
8496
|
+
* removal shifts the insertion index down by one). Always clears
|
|
8497
|
+
* `targetTabGroupId` so the dropped tab lands outside the group.
|
|
8498
|
+
*/
|
|
8499
|
+
_handleChipDrop(tabGroup, event) {
|
|
8500
|
+
const firstPanelId = tabGroup.panelIds[0];
|
|
8501
|
+
if (!firstPanelId) {
|
|
8502
|
+
return;
|
|
8503
|
+
}
|
|
8504
|
+
const insertionIndex = this._tabs.findIndex((x) => x.value.panel.id === firstPanelId);
|
|
8505
|
+
if (insertionIndex === -1) {
|
|
8506
|
+
return;
|
|
7429
8507
|
}
|
|
7430
|
-
|
|
7431
|
-
this.
|
|
8508
|
+
const data = getPanelData();
|
|
8509
|
+
const sourceIndex = data && data.groupId === this.group.id && data.panelId
|
|
8510
|
+
? this._tabs.findIndex((x) => x.value.panel.id === data.panelId)
|
|
8511
|
+
: -1;
|
|
8512
|
+
const adjustedIndex = insertionIndex -
|
|
8513
|
+
(sourceIndex !== -1 && sourceIndex < insertionIndex ? 1 : 0);
|
|
8514
|
+
this._onDrop.fire({
|
|
8515
|
+
event: event.nativeEvent,
|
|
8516
|
+
index: adjustedIndex,
|
|
8517
|
+
targetTabGroupId: null,
|
|
8518
|
+
});
|
|
7432
8519
|
}
|
|
7433
8520
|
/**
|
|
7434
8521
|
* Sets the broader container that is part of the same logical drop surface
|
|
@@ -7490,6 +8577,164 @@
|
|
|
7490
8577
|
}
|
|
7491
8578
|
return total / this._tabs.length;
|
|
7492
8579
|
}
|
|
8580
|
+
/**
|
|
8581
|
+
* Pointer-event entry point. The HTML5 path enters via the per-element
|
|
8582
|
+
* `dragover` listener; this one hit-tests the global pointer-drag
|
|
8583
|
+
* position against the tabs list and routes through the same shared
|
|
8584
|
+
* `_processDragOver` / `_processDragLeave` helpers.
|
|
8585
|
+
*/
|
|
8586
|
+
_handlePointerDragMove(clientX, clientY) {
|
|
8587
|
+
var _a;
|
|
8588
|
+
const sourceDoc = (_a = this._tabsList.ownerDocument) !== null && _a !== void 0 ? _a : document;
|
|
8589
|
+
const elAtPoint = sourceDoc.elementFromPoint(clientX, clientY);
|
|
8590
|
+
const inside = !!elAtPoint &&
|
|
8591
|
+
(this._tabsList.contains(elAtPoint) ||
|
|
8592
|
+
(!!this._extendedDropZone &&
|
|
8593
|
+
this._extendedDropZone.contains(elAtPoint)));
|
|
8594
|
+
if (!inside) {
|
|
8595
|
+
if (this._pointerInsideTabsList) {
|
|
8596
|
+
this._pointerInsideTabsList = false;
|
|
8597
|
+
this._processDragLeave(elAtPoint);
|
|
8598
|
+
}
|
|
8599
|
+
return;
|
|
8600
|
+
}
|
|
8601
|
+
this._pointerInsideTabsList = true;
|
|
8602
|
+
this._processDragOver(clientX);
|
|
8603
|
+
}
|
|
8604
|
+
/**
|
|
8605
|
+
* Shared body of the dragover entry point. Refreshes stale anim state
|
|
8606
|
+
* for a changed drag identity, initializes anim state for incoming
|
|
8607
|
+
* cross-group drags, and dispatches to the gap-following math in
|
|
8608
|
+
* `handleDragOver`. Returns true when this tabs list has taken
|
|
8609
|
+
* ownership of the drag — HTML5 callers use this to gate
|
|
8610
|
+
* `event.preventDefault()`.
|
|
8611
|
+
*/
|
|
8612
|
+
_processDragOver(clientX) {
|
|
8613
|
+
var _a, _b, _c, _d;
|
|
8614
|
+
if (this.accessor.options.disableDnd) {
|
|
8615
|
+
return false;
|
|
8616
|
+
}
|
|
8617
|
+
// Stale-state guard: if a previous drag's anim state is still here
|
|
8618
|
+
// but the current drag is a different identity, drop the stale one
|
|
8619
|
+
// so the new drag starts from a clean slate.
|
|
8620
|
+
if (this._animState) {
|
|
8621
|
+
const data = getPanelData();
|
|
8622
|
+
if ((data === null || data === void 0 ? void 0 : data.tabGroupId) &&
|
|
8623
|
+
data.groupId !== this.group.id &&
|
|
8624
|
+
this._animState.sourceTabGroupId !== data.tabGroupId) {
|
|
8625
|
+
this._animState = null;
|
|
8626
|
+
}
|
|
8627
|
+
}
|
|
8628
|
+
if (!this._animState) {
|
|
8629
|
+
const data = getPanelData();
|
|
8630
|
+
// In default animation mode, individual tab drops are handled
|
|
8631
|
+
// by per-tab Droptargets; only chip drags need tabs-list-level
|
|
8632
|
+
// handling so drops on void space still work.
|
|
8633
|
+
if (((_a = this.accessor.options.theme) === null || _a === void 0 ? void 0 : _a.tabAnimation) === 'default' &&
|
|
8634
|
+
!(data === null || data === void 0 ? void 0 : data.tabGroupId)) {
|
|
8635
|
+
return false;
|
|
8636
|
+
}
|
|
8637
|
+
if (data &&
|
|
8638
|
+
(data.panelId || data.tabGroupId) &&
|
|
8639
|
+
data.groupId !== this.group.id) {
|
|
8640
|
+
const avgWidth = this.getAverageTabWidth();
|
|
8641
|
+
if (data.tabGroupId) {
|
|
8642
|
+
// External group drag — look up the source group to
|
|
8643
|
+
// size the gap.
|
|
8644
|
+
const sourceGroup = this.accessor.getPanel(data.groupId);
|
|
8645
|
+
const sourceTg = sourceGroup === null || sourceGroup === void 0 ? void 0 : sourceGroup.model.getTabGroups().find((tg) => tg.id === data.tabGroupId);
|
|
8646
|
+
const panelCount = (_b = sourceTg === null || sourceTg === void 0 ? void 0 : sourceTg.panelIds.length) !== null && _b !== void 0 ? _b : 1;
|
|
8647
|
+
const groupGapWidth = avgWidth * panelCount + avgWidth;
|
|
8648
|
+
this._animState = {
|
|
8649
|
+
sourceTabId: '',
|
|
8650
|
+
sourceIndex: -1,
|
|
8651
|
+
tabPositions: this.snapshotTabPositions(),
|
|
8652
|
+
chipPositions: this._tabGroupManager.snapshotChipWidths(),
|
|
8653
|
+
currentInsertionIndex: null,
|
|
8654
|
+
targetTabGroupId: null,
|
|
8655
|
+
sourceTabGroupId: data.tabGroupId,
|
|
8656
|
+
sourceGroupPanelIds: sourceTg
|
|
8657
|
+
? new Set(sourceTg.panelIds)
|
|
8658
|
+
: new Set(),
|
|
8659
|
+
sourceChipWidth: avgWidth,
|
|
8660
|
+
cursorOffsetFromDragLeft: groupGapWidth / 2,
|
|
8661
|
+
sourceGapWidth: groupGapWidth,
|
|
8662
|
+
containerLeft: this._tabsList.getBoundingClientRect().left,
|
|
8663
|
+
};
|
|
8664
|
+
}
|
|
8665
|
+
else {
|
|
8666
|
+
this._animState = {
|
|
8667
|
+
sourceTabId: data.panelId,
|
|
8668
|
+
sourceIndex: -1,
|
|
8669
|
+
tabPositions: this.snapshotTabPositions(),
|
|
8670
|
+
chipPositions: this._tabGroupManager.snapshotChipWidths(),
|
|
8671
|
+
currentInsertionIndex: null,
|
|
8672
|
+
targetTabGroupId: null,
|
|
8673
|
+
sourceTabGroupId: null,
|
|
8674
|
+
sourceGroupPanelIds: null,
|
|
8675
|
+
sourceChipWidth: 0,
|
|
8676
|
+
cursorOffsetFromDragLeft: avgWidth / 2,
|
|
8677
|
+
sourceGapWidth: avgWidth,
|
|
8678
|
+
containerLeft: this._tabsList.getBoundingClientRect().left,
|
|
8679
|
+
};
|
|
8680
|
+
}
|
|
8681
|
+
}
|
|
8682
|
+
else {
|
|
8683
|
+
return false;
|
|
8684
|
+
}
|
|
8685
|
+
}
|
|
8686
|
+
// For intra-group drag (sourceIndex >= 0) the gap animation is the
|
|
8687
|
+
// sole visual indicator — clear any stale anchor overlay that may
|
|
8688
|
+
// have been set while the cursor was over the panel content area or
|
|
8689
|
+
// another zone. External drags (sourceIndex === -1) leave the
|
|
8690
|
+
// overlay to the individual tab Droptargets so cross-group
|
|
8691
|
+
// animation is not disrupted.
|
|
8692
|
+
if (this._animState.sourceIndex !== -1) {
|
|
8693
|
+
(_d = (_c = this.group.model.dropTargetContainer) === null || _c === void 0 ? void 0 : _c.model) === null || _d === void 0 ? void 0 : _d.clear();
|
|
8694
|
+
}
|
|
8695
|
+
this.handleDragOver({ clientX });
|
|
8696
|
+
return true;
|
|
8697
|
+
}
|
|
8698
|
+
/**
|
|
8699
|
+
* Shared body of the dragleave entry point. Preserves anim state when
|
|
8700
|
+
* the drag moves between tabs-list children, into the extended drop
|
|
8701
|
+
* zone, or into the void container; tears it down otherwise.
|
|
8702
|
+
*/
|
|
8703
|
+
_processDragLeave(related) {
|
|
8704
|
+
var _a, _b, _c;
|
|
8705
|
+
if (!this._animState) {
|
|
8706
|
+
return;
|
|
8707
|
+
}
|
|
8708
|
+
// Moves between children of the tabs list aren't real leaves.
|
|
8709
|
+
if (related && this._tabsList.contains(related)) {
|
|
8710
|
+
return;
|
|
8711
|
+
}
|
|
8712
|
+
// Moving into the broader drop zone (e.g. void container, left
|
|
8713
|
+
// actions) — keep anim state alive so external listeners can
|
|
8714
|
+
// continue the gap animation.
|
|
8715
|
+
if (related && ((_a = this._extendedDropZone) === null || _a === void 0 ? void 0 : _a.contains(related))) {
|
|
8716
|
+
this.resetTabTransforms();
|
|
8717
|
+
this._animState.currentInsertionIndex = null;
|
|
8718
|
+
return;
|
|
8719
|
+
}
|
|
8720
|
+
// Leaving toward the void container (empty header space to the
|
|
8721
|
+
// right): keep anim state so a drop can still land at the end.
|
|
8722
|
+
const isVoid = this._voidContainer &&
|
|
8723
|
+
related &&
|
|
8724
|
+
(related === this._voidContainer ||
|
|
8725
|
+
this._voidContainer.contains(related));
|
|
8726
|
+
if (isVoid) {
|
|
8727
|
+
return;
|
|
8728
|
+
}
|
|
8729
|
+
this.resetTabTransforms();
|
|
8730
|
+
if (this._animState.sourceIndex === -1) {
|
|
8731
|
+
(_c = (_b = this.group.model.dropTargetContainer) === null || _b === void 0 ? void 0 : _b.model) === null || _c === void 0 ? void 0 : _c.clear();
|
|
8732
|
+
this._animState = null;
|
|
8733
|
+
}
|
|
8734
|
+
else {
|
|
8735
|
+
this._animState.currentInsertionIndex = null;
|
|
8736
|
+
}
|
|
8737
|
+
}
|
|
7493
8738
|
handleDragOver(event) {
|
|
7494
8739
|
var _a, _b, _c, _d, _e;
|
|
7495
8740
|
if (!this._animState) {
|
|
@@ -7610,11 +8855,15 @@
|
|
|
7610
8855
|
if (!isInsideRange && !isJustBeforeGroup) {
|
|
7611
8856
|
continue;
|
|
7612
8857
|
}
|
|
7613
|
-
if (isGroupDrag) {
|
|
8858
|
+
if (isGroupDrag && isInsideRange) {
|
|
7614
8859
|
// A group cannot be dropped inside another group.
|
|
7615
8860
|
// Snap the insertion index to just before or just
|
|
7616
8861
|
// after this group based on cursor position relative
|
|
7617
|
-
// to the group's midpoint.
|
|
8862
|
+
// to the group's midpoint. Only applies when the
|
|
8863
|
+
// insertion would land *inside* the group — for
|
|
8864
|
+
// `isJustBeforeGroup`, the index is already outside
|
|
8865
|
+
// (immediately left of the group) and is a valid
|
|
8866
|
+
// drop position, so leave it untouched (issue #1264).
|
|
7618
8867
|
const groupMid = (firstIdx + lastIdx + 1) / 2;
|
|
7619
8868
|
if (insertionIndex < groupMid) {
|
|
7620
8869
|
insertionIndex = firstIdx;
|
|
@@ -7625,6 +8874,12 @@
|
|
|
7625
8874
|
// targetTabGroupId stays null
|
|
7626
8875
|
break;
|
|
7627
8876
|
}
|
|
8877
|
+
if (isGroupDrag && isJustBeforeGroup) {
|
|
8878
|
+
// Cursor is just before the group — accept this
|
|
8879
|
+
// index as-is. Groups can be dropped at the slot
|
|
8880
|
+
// immediately left of another group's first tab.
|
|
8881
|
+
break;
|
|
8882
|
+
}
|
|
7628
8883
|
if (isJustBeforeGroup) {
|
|
7629
8884
|
// Check whether only the source tab (or source group
|
|
7630
8885
|
// tabs) sits between insertionIndex and firstIdx.
|
|
@@ -7889,20 +9144,23 @@
|
|
|
7889
9144
|
* in the model, and run a FLIP animation.
|
|
7890
9145
|
*/
|
|
7891
9146
|
_commitGroupMove(sourceTabGroupId, insertionIndex) {
|
|
7892
|
-
var _a, _b
|
|
7893
|
-
// Read transfer data
|
|
7894
|
-
// _chipDragCleanup clears the global LocalSelectionTransfer
|
|
7895
|
-
// singleton which getPanelData() reads from.
|
|
9147
|
+
var _a, _b;
|
|
9148
|
+
// Read transfer data first.
|
|
7896
9149
|
const data = getPanelData();
|
|
7897
|
-
|
|
7898
|
-
|
|
9150
|
+
// Synchronously dispose the source chip's drag sources, which
|
|
9151
|
+
// clears the panelTransfer payload + iframe shield. Cross-group
|
|
9152
|
+
// moves dissolve the source chip on a microtask, which is too
|
|
9153
|
+
// late: a synchronous `getPanelData()` after this method (or any
|
|
9154
|
+
// sibling dragover handler firing in the same tick) would
|
|
9155
|
+
// otherwise see stale data still referencing the old tabGroupId.
|
|
9156
|
+
this._tabGroupManager.disposeChipDrag(sourceTabGroupId);
|
|
7899
9157
|
// Check if the tab group exists in this group (within-group reorder)
|
|
7900
9158
|
// or in another group (cross-group move).
|
|
7901
9159
|
const isLocal = this.group.model
|
|
7902
9160
|
.getTabGroups()
|
|
7903
9161
|
.some((tg) => tg.id === sourceTabGroupId);
|
|
7904
9162
|
if (isLocal) {
|
|
7905
|
-
if (((
|
|
9163
|
+
if (((_a = this.accessor.options.theme) === null || _a === void 0 ? void 0 : _a.tabAnimation) === 'smooth') {
|
|
7906
9164
|
this._clearGroupDragClasses(sourceTabGroupId);
|
|
7907
9165
|
const firstPositions = this.snapshotTabPositions();
|
|
7908
9166
|
this.resetTabTransforms();
|
|
@@ -7930,7 +9188,7 @@
|
|
|
7930
9188
|
this.accessor.moveGroupOrPanel({
|
|
7931
9189
|
from: {
|
|
7932
9190
|
groupId: data.groupId,
|
|
7933
|
-
tabGroupId: (
|
|
9191
|
+
tabGroupId: (_b = data.tabGroupId) !== null && _b !== void 0 ? _b : sourceTabGroupId,
|
|
7934
9192
|
},
|
|
7935
9193
|
to: {
|
|
7936
9194
|
group: this.group,
|
|
@@ -7958,22 +9216,27 @@
|
|
|
7958
9216
|
this._tabGroupManager.skipNextCollapseAnimation = true;
|
|
7959
9217
|
}
|
|
7960
9218
|
resetDragAnimation() {
|
|
7961
|
-
var _a, _b;
|
|
7962
9219
|
this._pendingCollapse = false;
|
|
7963
|
-
|
|
7964
|
-
//
|
|
7965
|
-
|
|
7966
|
-
|
|
7967
|
-
|
|
7968
|
-
|
|
7969
|
-
|
|
7970
|
-
|
|
7971
|
-
|
|
7972
|
-
|
|
7973
|
-
|
|
7974
|
-
|
|
7975
|
-
|
|
7976
|
-
|
|
9220
|
+
// After a drop, `tab.onDrop` consumes _animState (sets it to null)
|
|
9221
|
+
// and immediately calls `runFlipAnimation`, which sets transforms
|
|
9222
|
+
// and queues an rAF to trigger the CSS transition. dragend fires
|
|
9223
|
+
// synchronously on the source element BEFORE that rAF runs — if
|
|
9224
|
+
// we cleared transforms here we'd clobber the in-flight FLIP, so
|
|
9225
|
+
// gate the cleanup on _animState still being set (i.e. drag was
|
|
9226
|
+
// cancelled rather than dropped).
|
|
9227
|
+
if (this._animState) {
|
|
9228
|
+
this.resetTabTransforms();
|
|
9229
|
+
if (this._animState.sourceTabGroupId) {
|
|
9230
|
+
this._clearGroupDragClasses(this._animState.sourceTabGroupId);
|
|
9231
|
+
}
|
|
9232
|
+
else {
|
|
9233
|
+
this._removeClassInstantlyBatch(this._tabs.map((t) => t.value.element), 'dv-tab--dragging');
|
|
9234
|
+
}
|
|
9235
|
+
this._animState = null;
|
|
9236
|
+
// Restore any hidden underlines from group drags.
|
|
9237
|
+
for (const [, el] of this._tabGroupManager.groupUnderlines) {
|
|
9238
|
+
el.style.removeProperty('display');
|
|
9239
|
+
}
|
|
7977
9240
|
}
|
|
7978
9241
|
}
|
|
7979
9242
|
runFlipAnimation(firstPositions, sourceTabId, isCrossGroup = false, animRange) {
|
|
@@ -8466,12 +9729,14 @@
|
|
|
8466
9729
|
disableFloatingGroups: undefined,
|
|
8467
9730
|
floatingGroupBounds: undefined,
|
|
8468
9731
|
popoutUrl: undefined,
|
|
9732
|
+
nonce: undefined,
|
|
8469
9733
|
defaultRenderer: undefined,
|
|
8470
9734
|
defaultHeaderPosition: undefined,
|
|
8471
9735
|
debug: undefined,
|
|
8472
9736
|
rootOverlayModel: undefined,
|
|
8473
9737
|
locked: undefined,
|
|
8474
9738
|
disableDnd: undefined,
|
|
9739
|
+
dndStrategy: undefined,
|
|
8475
9740
|
className: undefined,
|
|
8476
9741
|
noPanelsOverlay: undefined,
|
|
8477
9742
|
dndEdges: undefined,
|
|
@@ -8481,6 +9746,7 @@
|
|
|
8481
9746
|
getTabContextMenuItems: undefined,
|
|
8482
9747
|
getTabGroupChipContextMenuItems: undefined,
|
|
8483
9748
|
createTabGroupChipComponent: undefined,
|
|
9749
|
+
createGroupDragGhostComponent: undefined,
|
|
8484
9750
|
tabGroupColors: undefined,
|
|
8485
9751
|
tabGroupAccent: undefined,
|
|
8486
9752
|
};
|
|
@@ -8655,6 +9921,10 @@
|
|
|
8655
9921
|
}
|
|
8656
9922
|
|
|
8657
9923
|
class DockviewDidDropEvent extends DockviewEvent {
|
|
9924
|
+
/**
|
|
9925
|
+
* `PointerEvent` for touch drags has no `dataTransfer`; use
|
|
9926
|
+
* `getData()` for the dockview payload regardless of input method.
|
|
9927
|
+
*/
|
|
8658
9928
|
get nativeEvent() {
|
|
8659
9929
|
return this.options.nativeEvent;
|
|
8660
9930
|
}
|
|
@@ -8759,29 +10029,28 @@
|
|
|
8759
10029
|
toggleClass(this.container, 'dv-groupview-floating', false);
|
|
8760
10030
|
toggleClass(this.container, 'dv-groupview-popout', false);
|
|
8761
10031
|
toggleClass(this.container, 'dv-groupview-edge', false);
|
|
10032
|
+
// Mouse and touch drop targets must agree on accepted zones.
|
|
10033
|
+
const applyZones = (zones) => {
|
|
10034
|
+
this.contentContainer.dropTarget.setTargetZones(zones);
|
|
10035
|
+
this.contentContainer.pointerDropTarget.setTargetZones(zones);
|
|
10036
|
+
};
|
|
8762
10037
|
switch (value.type) {
|
|
8763
10038
|
case 'grid':
|
|
8764
|
-
|
|
8765
|
-
'top',
|
|
8766
|
-
'bottom',
|
|
8767
|
-
'left',
|
|
8768
|
-
'right',
|
|
8769
|
-
'center',
|
|
8770
|
-
]);
|
|
10039
|
+
applyZones(['top', 'bottom', 'left', 'right', 'center']);
|
|
8771
10040
|
break;
|
|
8772
10041
|
case 'floating':
|
|
8773
|
-
|
|
8774
|
-
|
|
10042
|
+
applyZones(['center']);
|
|
10043
|
+
applyZones(value
|
|
8775
10044
|
? ['center']
|
|
8776
10045
|
: ['top', 'bottom', 'left', 'right', 'center']);
|
|
8777
10046
|
toggleClass(this.container, 'dv-groupview-floating', true);
|
|
8778
10047
|
break;
|
|
8779
10048
|
case 'popout':
|
|
8780
|
-
|
|
10049
|
+
applyZones(['center']);
|
|
8781
10050
|
toggleClass(this.container, 'dv-groupview-popout', true);
|
|
8782
10051
|
break;
|
|
8783
10052
|
case 'edge':
|
|
8784
|
-
|
|
10053
|
+
applyZones(['center']);
|
|
8785
10054
|
toggleClass(this.container, 'dv-groupview-edge', true);
|
|
8786
10055
|
break;
|
|
8787
10056
|
}
|
|
@@ -8907,6 +10176,8 @@
|
|
|
8907
10176
|
// noop
|
|
8908
10177
|
}), this.contentContainer.dropTarget.onDrop((event) => {
|
|
8909
10178
|
this.handleDropEvent('content', event.nativeEvent, event.position);
|
|
10179
|
+
}), this.contentContainer.pointerDropTarget.onDrop((event) => {
|
|
10180
|
+
this.handleDropEvent('content', event.nativeEvent, event.position);
|
|
8910
10181
|
}), this.tabsContainer.onWillShowOverlay((event) => {
|
|
8911
10182
|
this._onWillShowOverlay.fire(event);
|
|
8912
10183
|
}), this.contentContainer.dropTarget.onWillShowOverlay((event) => {
|
|
@@ -8917,6 +10188,14 @@
|
|
|
8917
10188
|
group: this.groupPanel,
|
|
8918
10189
|
getData: getPanelData,
|
|
8919
10190
|
}));
|
|
10191
|
+
}), this.contentContainer.pointerDropTarget.onWillShowOverlay((event) => {
|
|
10192
|
+
this._onWillShowOverlay.fire(new DockviewWillShowOverlayLocationEvent(event, {
|
|
10193
|
+
kind: 'content',
|
|
10194
|
+
panel: this.activePanel,
|
|
10195
|
+
api: this._api,
|
|
10196
|
+
group: this.groupPanel,
|
|
10197
|
+
getData: getPanelData,
|
|
10198
|
+
}));
|
|
8920
10199
|
}), this._onMove, this._onDidChange, this._onDidDrop, this._onWillDrop, this._onDidAddPanel, this._onDidRemovePanel, this._onDidActivePanelChange, this._onUnhandledDragOverEvent, this._onDidPanelTitleChange, this._onDidPanelParametersChange, this._onDidCreateTabGroup, this._onDidDestroyTabGroup, this._onDidAddPanelToTabGroup, this._onDidRemovePanelFromTabGroup, this._onDidTabGroupChange, this._onDidTabGroupCollapsedChange, this._onDidCreateTabGroup.event(() => {
|
|
8921
10200
|
this._scheduleTabGroupUpdate();
|
|
8922
10201
|
}), this._onDidDestroyTabGroup.event(() => {
|
|
@@ -9173,6 +10452,15 @@
|
|
|
9173
10452
|
refreshTabGroupAccent() {
|
|
9174
10453
|
this.tabsContainer.refreshTabGroupAccent();
|
|
9175
10454
|
}
|
|
10455
|
+
refreshWatermark() {
|
|
10456
|
+
var _a, _b;
|
|
10457
|
+
if (this.watermark) {
|
|
10458
|
+
this.watermark.element.remove();
|
|
10459
|
+
(_b = (_a = this.watermark).dispose) === null || _b === void 0 ? void 0 : _b.call(_a);
|
|
10460
|
+
this.watermark = undefined;
|
|
10461
|
+
}
|
|
10462
|
+
this.updateContainer();
|
|
10463
|
+
}
|
|
9176
10464
|
getTabGroupForPanel(panelId) {
|
|
9177
10465
|
return this._findTabGroupForPanel(panelId);
|
|
9178
10466
|
}
|
|
@@ -10003,6 +11291,18 @@
|
|
|
10003
11291
|
}
|
|
10004
11292
|
return this._group.model.location;
|
|
10005
11293
|
}
|
|
11294
|
+
get locked() {
|
|
11295
|
+
if (!this._group) {
|
|
11296
|
+
throw new Error(NOT_INITIALIZED_MESSAGE);
|
|
11297
|
+
}
|
|
11298
|
+
return this._group.locked;
|
|
11299
|
+
}
|
|
11300
|
+
set locked(value) {
|
|
11301
|
+
if (!this._group) {
|
|
11302
|
+
throw new Error(NOT_INITIALIZED_MESSAGE);
|
|
11303
|
+
}
|
|
11304
|
+
this._group.locked = value;
|
|
11305
|
+
}
|
|
10006
11306
|
constructor(id, accessor) {
|
|
10007
11307
|
super(id, '__dockviewgroup__');
|
|
10008
11308
|
this.accessor = accessor;
|
|
@@ -10593,6 +11893,11 @@
|
|
|
10593
11893
|
const didTitleChange = title !== this.title;
|
|
10594
11894
|
if (didTitleChange) {
|
|
10595
11895
|
this._title = title;
|
|
11896
|
+
// keep the view-model's cached init params in sync so that tab
|
|
11897
|
+
// renderers constructed lazily (e.g. the header overflow
|
|
11898
|
+
// dropdown via createTabRenderer) see the updated title
|
|
11899
|
+
// (#914).
|
|
11900
|
+
this.view.setTitle(title);
|
|
10596
11901
|
this.api._onDidTitleChange.fire({ title });
|
|
10597
11902
|
}
|
|
10598
11903
|
}
|
|
@@ -10753,6 +12058,14 @@
|
|
|
10753
12058
|
this.content.init(params);
|
|
10754
12059
|
this.tab.init(Object.assign(Object.assign({}, params), { tabLocation: 'header' }));
|
|
10755
12060
|
}
|
|
12061
|
+
setTitle(title) {
|
|
12062
|
+
// keep the cached init params in sync so that tab renderers created
|
|
12063
|
+
// lazily after the title changes (e.g. for the header overflow
|
|
12064
|
+
// dropdown) see the current title rather than the stale original.
|
|
12065
|
+
if (this._params) {
|
|
12066
|
+
this._params.title = title;
|
|
12067
|
+
}
|
|
12068
|
+
}
|
|
10756
12069
|
layout(width, height) {
|
|
10757
12070
|
var _a, _b;
|
|
10758
12071
|
(_b = (_a = this.content).layout) === null || _b === void 0 ? void 0 : _b.call(_a, width, height);
|
|
@@ -10886,7 +12199,12 @@
|
|
|
10886
12199
|
this.onDidChange = this._onDidChange.event;
|
|
10887
12200
|
this._onDidChangeEnd = new Emitter();
|
|
10888
12201
|
this.onDidChangeEnd = this._onDidChangeEnd.event;
|
|
10889
|
-
this.
|
|
12202
|
+
this._onDidStartMoving = new Emitter();
|
|
12203
|
+
/** Fires once per drag, the first time the float actually moves. */
|
|
12204
|
+
this.onDidStartMoving = this._onDidStartMoving.event;
|
|
12205
|
+
this._dragMove = new MutableDisposable();
|
|
12206
|
+
this._dragCancelled = false;
|
|
12207
|
+
this.addDisposables(this._onDidChange, this._onDidChangeEnd, this._onDidStartMoving, this._dragMove);
|
|
10890
12208
|
this._element.className = 'dv-resize-container';
|
|
10891
12209
|
this._isVisible = true;
|
|
10892
12210
|
this.setupResize('top');
|
|
@@ -10995,16 +12313,60 @@
|
|
|
10995
12313
|
result.height = element.height;
|
|
10996
12314
|
return result;
|
|
10997
12315
|
}
|
|
12316
|
+
/**
|
|
12317
|
+
* Abort an in-flight move-the-float drag. Used by the void container
|
|
12318
|
+
* when a redock long-press fires after the move started, so the ghost
|
|
12319
|
+
* gesture wins without the float continuing to follow the finger.
|
|
12320
|
+
* Does not emit `onDidChangeEnd` because no change is being committed.
|
|
12321
|
+
*/
|
|
12322
|
+
cancelPendingDrag() {
|
|
12323
|
+
if (!this._dragMove.value) {
|
|
12324
|
+
return;
|
|
12325
|
+
}
|
|
12326
|
+
this._dragCancelled = true;
|
|
12327
|
+
toggleClass(this._element, 'dv-resize-container-dragging', false);
|
|
12328
|
+
this._dragMove.value = exports.DockviewDisposable.NONE;
|
|
12329
|
+
}
|
|
10998
12330
|
setupDrag(dragTarget, options = { inDragMode: false }) {
|
|
10999
|
-
const
|
|
11000
|
-
const track = () => {
|
|
12331
|
+
const track = (captureTarget, pointerId) => {
|
|
11001
12332
|
let offset = null;
|
|
12333
|
+
let hasMoved = false;
|
|
12334
|
+
this._dragCancelled = false;
|
|
11002
12335
|
const iframes = disableIframePointEvents();
|
|
11003
|
-
|
|
12336
|
+
if (captureTarget &&
|
|
12337
|
+
typeof pointerId === 'number' &&
|
|
12338
|
+
typeof captureTarget.setPointerCapture === 'function') {
|
|
12339
|
+
try {
|
|
12340
|
+
captureTarget.setPointerCapture(pointerId);
|
|
12341
|
+
}
|
|
12342
|
+
catch (_a) {
|
|
12343
|
+
// ignore – non-fatal if the browser refuses capture
|
|
12344
|
+
}
|
|
12345
|
+
}
|
|
12346
|
+
const end = () => {
|
|
12347
|
+
toggleClass(this._element, 'dv-resize-container-dragging', false);
|
|
12348
|
+
this._dragMove.value = exports.DockviewDisposable.NONE;
|
|
12349
|
+
this._onDidChangeEnd.fire();
|
|
12350
|
+
};
|
|
12351
|
+
this._dragMove.value = new CompositeDisposable({
|
|
11004
12352
|
dispose: () => {
|
|
11005
12353
|
iframes.release();
|
|
12354
|
+
if (captureTarget &&
|
|
12355
|
+
typeof pointerId === 'number' &&
|
|
12356
|
+
typeof captureTarget.releasePointerCapture ===
|
|
12357
|
+
'function') {
|
|
12358
|
+
try {
|
|
12359
|
+
captureTarget.releasePointerCapture(pointerId);
|
|
12360
|
+
}
|
|
12361
|
+
catch (_a) {
|
|
12362
|
+
// ignore – pointer may already be released
|
|
12363
|
+
}
|
|
12364
|
+
}
|
|
11006
12365
|
},
|
|
11007
12366
|
}, addDisposableListener(window, 'pointermove', (e) => {
|
|
12367
|
+
if (this._dragCancelled) {
|
|
12368
|
+
return;
|
|
12369
|
+
}
|
|
11008
12370
|
const containerRect = this.options.container.getBoundingClientRect();
|
|
11009
12371
|
const x = e.clientX - containerRect.left;
|
|
11010
12372
|
const y = e.clientY - containerRect.top;
|
|
@@ -11041,13 +12403,13 @@
|
|
|
11041
12403
|
bounds.right = right;
|
|
11042
12404
|
}
|
|
11043
12405
|
this.setBounds(bounds);
|
|
11044
|
-
|
|
11045
|
-
|
|
11046
|
-
|
|
11047
|
-
|
|
11048
|
-
}));
|
|
12406
|
+
if (!hasMoved) {
|
|
12407
|
+
hasMoved = true;
|
|
12408
|
+
this._onDidStartMoving.fire();
|
|
12409
|
+
}
|
|
12410
|
+
}), addDisposableListener(window, 'pointerup', end), addDisposableListener(window, 'pointercancel', end));
|
|
11049
12411
|
};
|
|
11050
|
-
this.addDisposables(
|
|
12412
|
+
this.addDisposables(addDisposableListener(dragTarget, 'pointerdown', (event) => {
|
|
11051
12413
|
if (event.defaultPrevented) {
|
|
11052
12414
|
event.preventDefault();
|
|
11053
12415
|
return;
|
|
@@ -11057,7 +12419,7 @@
|
|
|
11057
12419
|
if (quasiDefaultPrevented(event)) {
|
|
11058
12420
|
return;
|
|
11059
12421
|
}
|
|
11060
|
-
track();
|
|
12422
|
+
track(dragTarget, event.pointerId);
|
|
11061
12423
|
}), addDisposableListener(this.options.content, 'pointerdown', (event) => {
|
|
11062
12424
|
if (event.defaultPrevented) {
|
|
11063
12425
|
return;
|
|
@@ -11068,7 +12430,7 @@
|
|
|
11068
12430
|
return;
|
|
11069
12431
|
}
|
|
11070
12432
|
if (event.shiftKey) {
|
|
11071
|
-
track();
|
|
12433
|
+
track(this.options.content, event.pointerId);
|
|
11072
12434
|
}
|
|
11073
12435
|
}), addDisposableListener(this.options.content, 'pointerdown', () => {
|
|
11074
12436
|
arialLevelTracker.push(this._element);
|
|
@@ -11086,6 +12448,19 @@
|
|
|
11086
12448
|
e.preventDefault();
|
|
11087
12449
|
let startPosition = null;
|
|
11088
12450
|
const iframes = disableIframePointEvents();
|
|
12451
|
+
const pointerId = e.pointerId;
|
|
12452
|
+
if (typeof resizeHandleElement.setPointerCapture === 'function') {
|
|
12453
|
+
try {
|
|
12454
|
+
resizeHandleElement.setPointerCapture(pointerId);
|
|
12455
|
+
}
|
|
12456
|
+
catch (_a) {
|
|
12457
|
+
// ignore – non-fatal if the browser refuses capture
|
|
12458
|
+
}
|
|
12459
|
+
}
|
|
12460
|
+
const end = () => {
|
|
12461
|
+
move.dispose();
|
|
12462
|
+
this._onDidChangeEnd.fire();
|
|
12463
|
+
};
|
|
11089
12464
|
move.value = new CompositeDisposable(addDisposableListener(window, 'pointermove', (e) => {
|
|
11090
12465
|
const containerRect = this.options.container.getBoundingClientRect();
|
|
11091
12466
|
const overlayRect = this._element.getBoundingClientRect();
|
|
@@ -11220,11 +12595,17 @@
|
|
|
11220
12595
|
}), {
|
|
11221
12596
|
dispose: () => {
|
|
11222
12597
|
iframes.release();
|
|
12598
|
+
if (typeof resizeHandleElement.releasePointerCapture ===
|
|
12599
|
+
'function') {
|
|
12600
|
+
try {
|
|
12601
|
+
resizeHandleElement.releasePointerCapture(pointerId);
|
|
12602
|
+
}
|
|
12603
|
+
catch (_a) {
|
|
12604
|
+
// ignore – pointer may already be released
|
|
12605
|
+
}
|
|
12606
|
+
}
|
|
11223
12607
|
},
|
|
11224
|
-
}, addDisposableListener(window, 'pointerup',
|
|
11225
|
-
move.dispose();
|
|
11226
|
-
this._onDidChangeEnd.fire();
|
|
11227
|
-
}));
|
|
12608
|
+
}, addDisposableListener(window, 'pointerup', end), addDisposableListener(window, 'pointercancel', end));
|
|
11228
12609
|
}));
|
|
11229
12610
|
}
|
|
11230
12611
|
getMinimumWidth(width) {
|
|
@@ -11672,7 +13053,9 @@
|
|
|
11672
13053
|
const externalDocument = externalWindow.document;
|
|
11673
13054
|
externalDocument.title = document.title;
|
|
11674
13055
|
externalDocument.body.appendChild(container);
|
|
11675
|
-
addStyles(externalDocument, window.document.styleSheets
|
|
13056
|
+
addStyles(externalDocument, window.document.styleSheets, {
|
|
13057
|
+
nonce: this.options.nonce,
|
|
13058
|
+
});
|
|
11676
13059
|
/**
|
|
11677
13060
|
* beforeunload must be registered after load for reasons I could not determine
|
|
11678
13061
|
* otherwise the beforeunload event will not fire when the window is closed
|
|
@@ -11747,6 +13130,14 @@
|
|
|
11747
13130
|
}
|
|
11748
13131
|
}
|
|
11749
13132
|
|
|
13133
|
+
function isCoarsePrimaryInput$1(win) {
|
|
13134
|
+
if (!win.matchMedia) {
|
|
13135
|
+
return false;
|
|
13136
|
+
}
|
|
13137
|
+
const coarse = win.matchMedia('(pointer: coarse)').matches;
|
|
13138
|
+
const fine = win.matchMedia('(pointer: fine)').matches;
|
|
13139
|
+
return coarse && !fine;
|
|
13140
|
+
}
|
|
11750
13141
|
class PopupService extends CompositeDisposable {
|
|
11751
13142
|
constructor(root, win = window) {
|
|
11752
13143
|
super();
|
|
@@ -11785,8 +13176,22 @@
|
|
|
11785
13176
|
wrapper.style.left = `${position.x - offsetX}px`;
|
|
11786
13177
|
this._element.appendChild(wrapper);
|
|
11787
13178
|
this._active = wrapper;
|
|
13179
|
+
// Outside-pointerdown dismissal is suppressed for a short grace
|
|
13180
|
+
// window after opening. Touch long-press callers (chip / tab context
|
|
13181
|
+
// menus) open the popover while the user's finger is still pressing
|
|
13182
|
+
// the source element — Android Chrome can dispatch a follow-up
|
|
13183
|
+
// synthetic pointerdown tied to the gesture, and the release-then-
|
|
13184
|
+
// retap motion can land just outside the wrapper. Either would
|
|
13185
|
+
// dismiss the popover before the user can see or interact with it.
|
|
13186
|
+
// The grace window is short enough that intentional outside taps
|
|
13187
|
+
// still feel responsive.
|
|
13188
|
+
const openedAt = Date.now();
|
|
13189
|
+
const POINTERDOWN_GRACE_MS = 200;
|
|
11788
13190
|
this._activeDisposable.value = new CompositeDisposable(addDisposableListener(this._window, 'pointerdown', (event) => {
|
|
11789
13191
|
var _a;
|
|
13192
|
+
if (Date.now() - openedAt < POINTERDOWN_GRACE_MS) {
|
|
13193
|
+
return;
|
|
13194
|
+
}
|
|
11790
13195
|
const target = event.target;
|
|
11791
13196
|
if (!(target instanceof HTMLElement)) {
|
|
11792
13197
|
return;
|
|
@@ -11804,6 +13209,18 @@
|
|
|
11804
13209
|
this.close();
|
|
11805
13210
|
}
|
|
11806
13211
|
}), addDisposableListener(this._window, 'resize', () => {
|
|
13212
|
+
// On touch-primary devices, common interactions resize the
|
|
13213
|
+
// window: on-screen keyboard pop, orientation change, browser
|
|
13214
|
+
// address-bar collapse. None of these mean "the user wants
|
|
13215
|
+
// the popover dismissed". Specifically, focusing the chip
|
|
13216
|
+
// context menu's rename input pops the keyboard, which would
|
|
13217
|
+
// otherwise close the menu the moment the user goes to edit
|
|
13218
|
+
// it. Desktop / hybrid input keeps the existing behaviour —
|
|
13219
|
+
// there a resize genuinely means the user has resized the
|
|
13220
|
+
// window and the popover position is now stale.
|
|
13221
|
+
if (isCoarsePrimaryInput$1(this._window)) {
|
|
13222
|
+
return;
|
|
13223
|
+
}
|
|
11807
13224
|
this.close();
|
|
11808
13225
|
}));
|
|
11809
13226
|
this._window.requestAnimationFrame(() => {
|
|
@@ -11860,6 +13277,14 @@
|
|
|
11860
13277
|
el.setAttribute('role', 'separator');
|
|
11861
13278
|
return el;
|
|
11862
13279
|
}
|
|
13280
|
+
function isCoarsePrimaryInput() {
|
|
13281
|
+
if (typeof window === 'undefined' || !window.matchMedia) {
|
|
13282
|
+
return false;
|
|
13283
|
+
}
|
|
13284
|
+
const coarse = window.matchMedia('(pointer: coarse)').matches;
|
|
13285
|
+
const fine = window.matchMedia('(pointer: fine)').matches;
|
|
13286
|
+
return coarse && !fine;
|
|
13287
|
+
}
|
|
11863
13288
|
function buildRenameInput(tabGroup) {
|
|
11864
13289
|
const wrapper = document.createElement('div');
|
|
11865
13290
|
wrapper.className = 'dv-context-menu-rename';
|
|
@@ -11880,10 +13305,17 @@
|
|
|
11880
13305
|
e.stopPropagation();
|
|
11881
13306
|
});
|
|
11882
13307
|
wrapper.appendChild(input);
|
|
11883
|
-
|
|
11884
|
-
|
|
11885
|
-
|
|
11886
|
-
|
|
13308
|
+
// Skip auto-focus on touch-primary devices: focusing the input pops the
|
|
13309
|
+
// on-screen keyboard, which fires `window resize`, which `PopupService`
|
|
13310
|
+
// listens to and uses to dismiss the popover — so the menu opens, the
|
|
13311
|
+
// keyboard appears, and the menu immediately closes before the user can
|
|
13312
|
+
// type. The user can still tap the input to focus it intentionally.
|
|
13313
|
+
if (!isCoarsePrimaryInput()) {
|
|
13314
|
+
requestAnimationFrame(() => {
|
|
13315
|
+
input.focus();
|
|
13316
|
+
input.select();
|
|
13317
|
+
});
|
|
13318
|
+
}
|
|
11887
13319
|
return wrapper;
|
|
11888
13320
|
}
|
|
11889
13321
|
function buildColorPicker(tabGroup, palette) {
|
|
@@ -12798,7 +14230,7 @@
|
|
|
12798
14230
|
return this._popoutRestorationPromise;
|
|
12799
14231
|
}
|
|
12800
14232
|
constructor(container, options) {
|
|
12801
|
-
var _a, _b, _c, _d, _e, _f;
|
|
14233
|
+
var _a, _b, _c, _d, _e, _f, _g;
|
|
12802
14234
|
super(container, {
|
|
12803
14235
|
proportionalLayout: true,
|
|
12804
14236
|
orientation: exports.Orientation.HORIZONTAL,
|
|
@@ -12862,6 +14294,7 @@
|
|
|
12862
14294
|
this._floatingGroups = [];
|
|
12863
14295
|
this._popoutGroups = [];
|
|
12864
14296
|
this._popoutRestorationPromise = Promise.resolve();
|
|
14297
|
+
this._popoutRestorationCleanups = new Set();
|
|
12865
14298
|
this._onDidRemoveGroup = new Emitter();
|
|
12866
14299
|
this.onDidRemoveGroup = this._onDidRemoveGroup.event;
|
|
12867
14300
|
this._onDidAddGroup = new Emitter();
|
|
@@ -12896,37 +14329,51 @@
|
|
|
12896
14329
|
this._floatingOverlayHost = document.createElement('div');
|
|
12897
14330
|
this._floatingOverlayHost.className = 'dv-floating-overlay-host';
|
|
12898
14331
|
this._shellManager.element.appendChild(this._floatingOverlayHost);
|
|
12899
|
-
|
|
12900
|
-
|
|
12901
|
-
|
|
12902
|
-
|
|
12903
|
-
if (data) {
|
|
12904
|
-
if (data.viewId !== this.id) {
|
|
12905
|
-
return false;
|
|
12906
|
-
}
|
|
12907
|
-
if (position === 'center') {
|
|
12908
|
-
// center drop target is only allowed if there are no panels in the grid
|
|
12909
|
-
// floating panels are allowed
|
|
12910
|
-
return this.gridview.length === 0;
|
|
12911
|
-
}
|
|
12912
|
-
return true;
|
|
12913
|
-
}
|
|
12914
|
-
if (position === 'center' && this.gridview.length !== 0) {
|
|
12915
|
-
/**
|
|
12916
|
-
* for external events only show the four-corner drag overlays, disable
|
|
12917
|
-
* the center position so that external drag events can fall through to the group
|
|
12918
|
-
* and panel drop target handlers
|
|
12919
|
-
*/
|
|
14332
|
+
const rootCanDisplayOverlay = (event, position) => {
|
|
14333
|
+
const data = getPanelData();
|
|
14334
|
+
if (data) {
|
|
14335
|
+
if (data.viewId !== this.id) {
|
|
12920
14336
|
return false;
|
|
12921
14337
|
}
|
|
12922
|
-
|
|
12923
|
-
|
|
12924
|
-
|
|
12925
|
-
|
|
14338
|
+
if (position === 'center') {
|
|
14339
|
+
// center drop target is only allowed if there are no panels in the grid
|
|
14340
|
+
// floating panels are allowed
|
|
14341
|
+
return this.gridview.length === 0;
|
|
14342
|
+
}
|
|
14343
|
+
return true;
|
|
14344
|
+
}
|
|
14345
|
+
if (position === 'center' && this.gridview.length !== 0) {
|
|
14346
|
+
/**
|
|
14347
|
+
* for external events only show the four-corner drag overlays, disable
|
|
14348
|
+
* the center position so that external drag events can fall through to the group
|
|
14349
|
+
* and panel drop target handlers
|
|
14350
|
+
*/
|
|
14351
|
+
return false;
|
|
14352
|
+
}
|
|
14353
|
+
const firedEvent = new DockviewUnhandledDragOverEvent(event, 'edge', position, getPanelData);
|
|
14354
|
+
this._onUnhandledDragOverEvent.fire(firedEvent);
|
|
14355
|
+
return firedEvent.isAccepted;
|
|
14356
|
+
};
|
|
14357
|
+
this._rootDropTarget = html5Backend.createDropTarget(this.element, {
|
|
14358
|
+
className: 'dv-drop-target-edge',
|
|
14359
|
+
canDisplayOverlay: rootCanDisplayOverlay,
|
|
12926
14360
|
acceptedTargetZones: ['top', 'bottom', 'left', 'right', 'center'],
|
|
12927
14361
|
overlayModel: (_f = options.rootOverlayModel) !== null && _f !== void 0 ? _f : DEFAULT_ROOT_OVERLAY_MODEL,
|
|
12928
14362
|
getOverrideTarget: () => { var _a; return (_a = this.rootDropTargetContainer) === null || _a === void 0 ? void 0 : _a.model; },
|
|
12929
14363
|
});
|
|
14364
|
+
this._rootPointerDropTarget = pointerBackend.createDropTarget(this.element, {
|
|
14365
|
+
className: 'dv-drop-target-edge',
|
|
14366
|
+
canDisplayOverlay: rootCanDisplayOverlay,
|
|
14367
|
+
acceptedTargetZones: [
|
|
14368
|
+
'top',
|
|
14369
|
+
'bottom',
|
|
14370
|
+
'left',
|
|
14371
|
+
'right',
|
|
14372
|
+
'center',
|
|
14373
|
+
],
|
|
14374
|
+
overlayModel: (_g = options.rootOverlayModel) !== null && _g !== void 0 ? _g : DEFAULT_ROOT_OVERLAY_MODEL,
|
|
14375
|
+
getOverrideTarget: () => { var _a; return (_a = this.rootDropTargetContainer) === null || _a === void 0 ? void 0 : _a.model; },
|
|
14376
|
+
});
|
|
12930
14377
|
this.updateDropTargetModel(options);
|
|
12931
14378
|
toggleClass(this.gridview.element, 'dv-dockview', true);
|
|
12932
14379
|
toggleClass(this.element, 'dv-debug', !!options.debug);
|
|
@@ -12967,6 +14414,14 @@
|
|
|
12967
14414
|
this._bufferOnDidLayoutChange.fire();
|
|
12968
14415
|
}), exports.DockviewDisposable.from(() => {
|
|
12969
14416
|
var _a;
|
|
14417
|
+
// Cancel any pending popout-restoration timers scheduled by
|
|
14418
|
+
// fromJSON so they don't open new browser windows after
|
|
14419
|
+
// dispose, and resolve their promises so callers awaiting
|
|
14420
|
+
// popoutRestorationPromise don't hang. See issue #851.
|
|
14421
|
+
for (const cleanup of [...this._popoutRestorationCleanups]) {
|
|
14422
|
+
cleanup();
|
|
14423
|
+
}
|
|
14424
|
+
this._popoutRestorationCleanups.clear();
|
|
12970
14425
|
// iterate over a copy of the array since .dispose() mutates the original array
|
|
12971
14426
|
for (const group of [...this._floatingGroups]) {
|
|
12972
14427
|
group.dispose();
|
|
@@ -12980,7 +14435,7 @@
|
|
|
12980
14435
|
d.dispose();
|
|
12981
14436
|
}
|
|
12982
14437
|
this._edgeGroupDisposables.clear();
|
|
12983
|
-
}), this._rootDropTarget, this._rootDropTarget.onWillShowOverlay((event) => {
|
|
14438
|
+
}), this._rootDropTarget, this._rootPointerDropTarget, exports.DockviewEvent.any(this._rootDropTarget.onWillShowOverlay, this._rootPointerDropTarget.onWillShowOverlay)((event) => {
|
|
12984
14439
|
if (this.gridview.length > 0 && event.position === 'center') {
|
|
12985
14440
|
// option only available when no panels in primary grid
|
|
12986
14441
|
return;
|
|
@@ -12992,7 +14447,7 @@
|
|
|
12992
14447
|
group: undefined,
|
|
12993
14448
|
getData: getPanelData,
|
|
12994
14449
|
}));
|
|
12995
|
-
}), this._rootDropTarget.onDrop((event) => {
|
|
14450
|
+
}), exports.DockviewEvent.any(this._rootDropTarget.onDrop, this._rootPointerDropTarget.onDrop)((event) => {
|
|
12996
14451
|
var _a;
|
|
12997
14452
|
const willDropEvent = new DockviewWillDropEvent({
|
|
12998
14453
|
nativeEvent: event.nativeEvent,
|
|
@@ -13030,7 +14485,7 @@
|
|
|
13030
14485
|
getData: getPanelData,
|
|
13031
14486
|
}));
|
|
13032
14487
|
}
|
|
13033
|
-
})
|
|
14488
|
+
}));
|
|
13034
14489
|
}
|
|
13035
14490
|
setVisible(panel, visible) {
|
|
13036
14491
|
switch (panel.api.location.type) {
|
|
@@ -13063,7 +14518,7 @@
|
|
|
13063
14518
|
return (_a = this._popoutPopupServices.get(group.id)) !== null && _a !== void 0 ? _a : this.popupService;
|
|
13064
14519
|
}
|
|
13065
14520
|
addPopoutGroup(itemToPopout, options) {
|
|
13066
|
-
var _a, _b, _c, _d, _e;
|
|
14521
|
+
var _a, _b, _c, _d, _e, _f;
|
|
13067
14522
|
if (itemToPopout instanceof DockviewGroupPanel &&
|
|
13068
14523
|
itemToPopout.model.location.type === 'edge') {
|
|
13069
14524
|
// edge groups are permanent structural elements and cannot be popped out
|
|
@@ -13098,6 +14553,7 @@
|
|
|
13098
14553
|
height: box.height,
|
|
13099
14554
|
onDidOpen: options === null || options === void 0 ? void 0 : options.onDidOpen,
|
|
13100
14555
|
onWillClose: options === null || options === void 0 ? void 0 : options.onWillClose,
|
|
14556
|
+
nonce: (_f = this.options) === null || _f === void 0 ? void 0 : _f.nonce,
|
|
13101
14557
|
});
|
|
13102
14558
|
const popoutWindowDisposable = new CompositeDisposable(_window, _window.onDidClose(() => {
|
|
13103
14559
|
popoutWindowDisposable.dispose();
|
|
@@ -13515,7 +14971,7 @@
|
|
|
13515
14971
|
}
|
|
13516
14972
|
}
|
|
13517
14973
|
updateOptions(options) {
|
|
13518
|
-
var _a, _b, _c;
|
|
14974
|
+
var _a, _b, _c, _d, _e;
|
|
13519
14975
|
super.updateOptions(options);
|
|
13520
14976
|
if ('floatingGroupBounds' in options) {
|
|
13521
14977
|
for (const group of this._floatingGroups) {
|
|
@@ -13541,9 +14997,12 @@
|
|
|
13541
14997
|
}
|
|
13542
14998
|
this.updateDropTargetModel(options);
|
|
13543
14999
|
const oldDisableDnd = this.options.disableDnd;
|
|
15000
|
+
const oldDndStrategy = this.options.dndStrategy;
|
|
13544
15001
|
this._options = Object.assign(Object.assign({}, this.options), options);
|
|
13545
15002
|
const newDisableDnd = this.options.disableDnd;
|
|
13546
|
-
|
|
15003
|
+
const newDndStrategy = this.options.dndStrategy;
|
|
15004
|
+
if (oldDisableDnd !== newDisableDnd ||
|
|
15005
|
+
oldDndStrategy !== newDndStrategy) {
|
|
13547
15006
|
this.updateDragAndDropState();
|
|
13548
15007
|
}
|
|
13549
15008
|
if ('theme' in options) {
|
|
@@ -13556,8 +15015,19 @@
|
|
|
13556
15015
|
group.model.updateHeaderActions();
|
|
13557
15016
|
}
|
|
13558
15017
|
}
|
|
15018
|
+
if ('createWatermarkComponent' in options) {
|
|
15019
|
+
if (this._watermark) {
|
|
15020
|
+
this._watermark.element.parentElement.remove();
|
|
15021
|
+
(_d = (_c = this._watermark).dispose) === null || _d === void 0 ? void 0 : _d.call(_c);
|
|
15022
|
+
this._watermark = null;
|
|
15023
|
+
}
|
|
15024
|
+
this.updateWatermark();
|
|
15025
|
+
for (const group of this.groups) {
|
|
15026
|
+
group.model.refreshWatermark();
|
|
15027
|
+
}
|
|
15028
|
+
}
|
|
13559
15029
|
if ('tabGroupColors' in options || 'tabGroupAccent' in options) {
|
|
13560
|
-
this._tabGroupColorPalette.setEntries((
|
|
15030
|
+
this._tabGroupColorPalette.setEntries((_e = this._options.tabGroupColors) !== null && _e !== void 0 ? _e : DEFAULT_TAB_GROUP_COLORS);
|
|
13561
15031
|
this._tabGroupColorPalette.enabled =
|
|
13562
15032
|
this._options.tabGroupAccent !== 'off';
|
|
13563
15033
|
for (const group of this.groups) {
|
|
@@ -13983,7 +15453,23 @@
|
|
|
13983
15453
|
const group = createGroupFromSerializedState(data);
|
|
13984
15454
|
// Add a small delay for each popup after the first to avoid browser popup blocking
|
|
13985
15455
|
const popoutPromise = new Promise((resolve) => {
|
|
13986
|
-
|
|
15456
|
+
const cleanup = () => {
|
|
15457
|
+
this._popoutRestorationCleanups.delete(cleanup);
|
|
15458
|
+
clearTimeout(handle);
|
|
15459
|
+
resolve();
|
|
15460
|
+
};
|
|
15461
|
+
const handle = setTimeout(() => {
|
|
15462
|
+
this._popoutRestorationCleanups.delete(cleanup);
|
|
15463
|
+
// Guard against the component being disposed before
|
|
15464
|
+
// this timer fires. Under React StrictMode the
|
|
15465
|
+
// component is mounted -> disposed -> remounted, and
|
|
15466
|
+
// without this guard the first instance's queued
|
|
15467
|
+
// restoration would open a second popout window.
|
|
15468
|
+
// See issue #851.
|
|
15469
|
+
if (this.isDisposed) {
|
|
15470
|
+
resolve();
|
|
15471
|
+
return;
|
|
15472
|
+
}
|
|
13987
15473
|
this.addPopoutGroup(group, {
|
|
13988
15474
|
position: position !== null && position !== void 0 ? position : undefined,
|
|
13989
15475
|
overridePopoutGroup: gridReferenceGroup
|
|
@@ -13996,6 +15482,7 @@
|
|
|
13996
15482
|
});
|
|
13997
15483
|
resolve();
|
|
13998
15484
|
}, index * DESERIALIZATION_POPOUT_DELAY_MS); // 100ms delay between each popup
|
|
15485
|
+
this._popoutRestorationCleanups.add(cleanup);
|
|
13999
15486
|
});
|
|
14000
15487
|
popoutPromises.push(popoutPromise);
|
|
14001
15488
|
});
|
|
@@ -14526,8 +16013,11 @@
|
|
|
14526
16013
|
* the source group is a popout group with a single panel
|
|
14527
16014
|
*
|
|
14528
16015
|
* 1. remove the panel from the group without triggering any events
|
|
14529
|
-
* 2. remove the popout group
|
|
14530
|
-
*
|
|
16016
|
+
* 2. remove the popout group — this may cascade-remove the empty
|
|
16017
|
+
* reference group it left behind in the main grid (see
|
|
16018
|
+
* doRemoveGroup for popout groups), which can shift grid indices
|
|
16019
|
+
* 3. recompute the target location now that the grid is stable
|
|
16020
|
+
* 4. create a new group at the recomputed location and add that panel
|
|
14531
16021
|
*/
|
|
14532
16022
|
const popoutGroup = this._popoutGroups.find((group) => group.popoutGroup === sourceGroup);
|
|
14533
16023
|
const removedPanel = this.movingLock(() => popoutGroup.popoutGroup.model.removePanel(popoutGroup.popoutGroup.panels[0], {
|
|
@@ -14535,7 +16025,8 @@
|
|
|
14535
16025
|
skipSetActiveGroup: true,
|
|
14536
16026
|
}));
|
|
14537
16027
|
this.doRemoveGroup(sourceGroup, { skipActive: true });
|
|
14538
|
-
const
|
|
16028
|
+
const updatedTargetLocation = getRelativeLocation(this.gridview.orientation, getGridLocation(destinationGroup.element), destinationTarget);
|
|
16029
|
+
const newGroup = this.createGroupAtLocation(updatedTargetLocation);
|
|
14539
16030
|
this.movingLock(() => newGroup.model.openPanel(removedPanel, {
|
|
14540
16031
|
skipSetActive: true,
|
|
14541
16032
|
}));
|
|
@@ -15075,15 +16566,18 @@
|
|
|
15075
16566
|
}
|
|
15076
16567
|
updateDropTargetModel(options) {
|
|
15077
16568
|
if ('dndEdges' in options) {
|
|
15078
|
-
|
|
15079
|
-
|
|
15080
|
-
|
|
16569
|
+
const disabled = typeof options.dndEdges === 'boolean' &&
|
|
16570
|
+
options.dndEdges === false;
|
|
16571
|
+
this._rootDropTarget.disabled = disabled;
|
|
16572
|
+
this._rootPointerDropTarget.disabled = disabled;
|
|
15081
16573
|
if (typeof options.dndEdges === 'object' &&
|
|
15082
16574
|
options.dndEdges !== null) {
|
|
15083
16575
|
this._rootDropTarget.setOverlayModel(options.dndEdges);
|
|
16576
|
+
this._rootPointerDropTarget.setOverlayModel(options.dndEdges);
|
|
15084
16577
|
}
|
|
15085
16578
|
else {
|
|
15086
16579
|
this._rootDropTarget.setOverlayModel(DEFAULT_ROOT_OVERLAY_MODEL);
|
|
16580
|
+
this._rootPointerDropTarget.setOverlayModel(DEFAULT_ROOT_OVERLAY_MODEL);
|
|
15087
16581
|
}
|
|
15088
16582
|
}
|
|
15089
16583
|
if ('rootOverlayModel' in options) {
|