Skip to content

Commit 724d560

Browse files
authored
Merge pull request #782 from jasongrout/splitpanel-pointercapture
In #760, it was reported that dragging a handle near an iframe can lose the drag events when the mouse goes over the iframe. This attempts to use the pointer capture semantics to ensure that the drag events continue to go to the splitpanel or dockpanel. It is similar to the solution at eclipse-theia/theia#15643. We make the pointer capture optional to de-risk releasing this in a patch release and to make the testing (where we manually construct pointer events) still pass.
2 parents a4b7e46 + 5ea9716 commit 724d560

2 files changed

Lines changed: 48 additions & 2 deletions

File tree

packages/widgets/src/dockpanel.ts

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -721,6 +721,17 @@ export class DockPanel extends Widget {
721721
this._document.addEventListener('pointermove', this, true);
722722
this._document.addEventListener('contextmenu', this, true);
723723

724+
// Set the pointer capture to this split panel, ensuring the document
725+
// listeners above will be triggered even if the pointer drifts over another
726+
// document, like an iframe.
727+
let pointerId = event.pointerId;
728+
try {
729+
this.node.setPointerCapture(pointerId);
730+
} catch (e) {
731+
// Pointer capture is nice to try, but may fail. In that case, ignore the
732+
// failure.
733+
}
734+
724735
// Compute the offset deltas for the handle press.
725736
let rect = handle.getBoundingClientRect();
726737
let deltaX = event.clientX - rect.left;
@@ -729,7 +740,7 @@ export class DockPanel extends Widget {
729740
// Override the cursor and store the press data.
730741
let style = window.getComputedStyle(handle);
731742
let override = Drag.overrideCursor(style.cursor!, this._document);
732-
this._pressData = { handle, deltaX, deltaY, override };
743+
this._pressData = { handle, deltaX, deltaY, override, pointerId };
733744
}
734745

735746
/**
@@ -784,6 +795,12 @@ export class DockPanel extends Widget {
784795
return;
785796
}
786797

798+
// Release the pointer capture if it is set.
799+
let pointerId = this._pressData.pointerId;
800+
if (this.node.hasPointerCapture(pointerId)) {
801+
this.node.releasePointerCapture(pointerId);
802+
}
803+
787804
// Clear the override cursor.
788805
this._pressData.override.dispose();
789806
this._pressData = null;
@@ -1466,6 +1483,11 @@ namespace Private {
14661483
* The disposable which will clear the override cursor.
14671484
*/
14681485
override: IDisposable;
1486+
1487+
/**
1488+
* Pointer ID of the press event.
1489+
*/
1490+
pointerId: number;
14691491
}
14701492

14711493
/**

packages/widgets/src/splitpanel.ts

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -262,6 +262,17 @@ export class SplitPanel extends Panel {
262262
document.addEventListener('keydown', this, true);
263263
document.addEventListener('contextmenu', this, true);
264264

265+
// Set the pointer capture to this split panel, ensuring the document
266+
// listeners above will be triggered even if the pointer drifts over another
267+
// document, like an iframe.
268+
let pointerId = event.pointerId;
269+
try {
270+
this.node.setPointerCapture(pointerId);
271+
} catch (e) {
272+
// Pointer capture is nice to try, but may fail. In that case, ignore the
273+
// failure.
274+
}
275+
265276
// Compute the offset delta for the handle press.
266277
let delta: number;
267278
let handle = layout.handles[index];
@@ -275,7 +286,7 @@ export class SplitPanel extends Panel {
275286
// Override the cursor and store the press data.
276287
let style = window.getComputedStyle(handle);
277288
let override = Drag.overrideCursor(style.cursor!);
278-
this._pressData = { index, delta, override };
289+
this._pressData = { index, delta, override, pointerId };
279290
}
280291

281292
/**
@@ -326,8 +337,16 @@ export class SplitPanel extends Panel {
326337
return;
327338
}
328339

340+
// Release the pointer capture if it is set.
341+
let pointerId = this._pressData.pointerId;
342+
if (this.node.hasPointerCapture(pointerId)) {
343+
this.node.releasePointerCapture(pointerId);
344+
}
345+
329346
// Clear the override cursor.
330347
this._pressData.override.dispose();
348+
349+
// Clear the press data.
331350
this._pressData = null;
332351

333352
// Emit the handle moved signal.
@@ -471,6 +490,11 @@ namespace Private {
471490
* The disposable which will clear the override cursor.
472491
*/
473492
override: IDisposable;
493+
494+
/**
495+
* Pointer ID of the press event.
496+
*/
497+
pointerId: number;
474498
}
475499

476500
/**

0 commit comments

Comments
 (0)