Skip to content

Commit 1fa4474

Browse files
Backport PR #16647: Do not block shift-click mouse up handler on active cell (#16663)
Co-authored-by: Eddie Groshev <eddie_g_89@hotmail.com>
1 parent c639643 commit 1fa4474

2 files changed

Lines changed: 62 additions & 4 deletions

File tree

packages/notebook/src/widget.ts

Lines changed: 26 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2487,6 +2487,13 @@ export class Notebook extends StaticNotebook {
24872487
}
24882488
// Enter selecting mode
24892489
this._mouseMode = 'select';
2490+
2491+
// We don't want to block the shift-click mouse up handler
2492+
// when the current cell is (and remains) the active cell.
2493+
this._selectData = {
2494+
startedOnActiveCell: index == this.activeCellIndex,
2495+
startingCellIndex: this.activeCellIndex
2496+
};
24902497
document.addEventListener('mouseup', this, true);
24912498
document.addEventListener('mousemove', this, true);
24922499
} else if (button === 0 && !shiftKey) {
@@ -2532,8 +2539,21 @@ export class Notebook extends StaticNotebook {
25322539
* Handle the `'mouseup'` event on the document.
25332540
*/
25342541
private _evtDocumentMouseup(event: MouseEvent): void {
2535-
event.preventDefault();
2536-
event.stopPropagation();
2542+
const [, index] = this._findEventTargetAndCell(event);
2543+
2544+
let shouldPreventDefault = true;
2545+
if (this._mouseMode === 'select' && this._selectData) {
2546+
// User did not move the mouse over to a difference cell, so there was no selection
2547+
const { startedOnActiveCell, startingCellIndex } = this._selectData;
2548+
if (startedOnActiveCell && index === startingCellIndex) {
2549+
shouldPreventDefault = false;
2550+
}
2551+
this._selectData = null;
2552+
}
2553+
if (shouldPreventDefault) {
2554+
event.preventDefault();
2555+
event.stopPropagation();
2556+
}
25372557

25382558
// Remove the event listeners we put on the document
25392559
document.removeEventListener('mousemove', this, true);
@@ -2542,8 +2562,6 @@ export class Notebook extends StaticNotebook {
25422562
if (this._mouseMode === 'couldDrag') {
25432563
// We didn't end up dragging if we are here, so treat it as a click event.
25442564

2545-
const [, index] = this._findEventTargetAndCell(event);
2546-
25472565
this.deselectAll();
25482566
this.activeCellIndex = index;
25492567
// Focus notebook if active cell changes but does not have focus.
@@ -2955,6 +2973,10 @@ export class Notebook extends StaticNotebook {
29552973
pressY: number;
29562974
index: number;
29572975
} | null = null;
2976+
private _selectData: {
2977+
startedOnActiveCell: boolean;
2978+
startingCellIndex: number;
2979+
} | null = null;
29582980
private _mouseMode: 'select' | 'couldDrag' | null = null;
29592981
private _activeCellChanged = new Signal<this, Cell | null>(this);
29602982
private _stateChanged = new Signal<this, IChangedArgs<any>>(this);

packages/notebook/test/widget.spec.ts

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1233,6 +1233,21 @@ describe('@jupyter/notebook', () => {
12331233
it('should extend selection if invoked with shift', () => {
12341234
widget.activeCellIndex = 3;
12351235

1236+
// shift click no-op
1237+
simulate(widget.widgets[3].node, 'mousedown', { shiftKey: true });
1238+
expect(widget.activeCellIndex).toBe(3);
1239+
expect(selected(widget)).toEqual([]);
1240+
// test that selecting mode handler does not prevent default
1241+
// if no cells were selected; in the selecting mode we listen
1242+
// to the `mouseup` event to stop selecting when the mouse button gets
1243+
// released; this event gets default prevented as handled by the notebook.
1244+
const mouseUpEvent = new MouseEvent('mouseup', {
1245+
bubbles: true,
1246+
cancelable: true
1247+
});
1248+
widget.widgets[3].node.dispatchEvent(mouseUpEvent);
1249+
expect(mouseUpEvent.defaultPrevented).toBe(false);
1250+
12361251
// shift click below
12371252
simulate(widget.widgets[4].node, 'mousedown', { shiftKey: true });
12381253
expect(widget.activeCellIndex).toBe(4);
@@ -1252,6 +1267,27 @@ describe('@jupyter/notebook', () => {
12521267
simulate(widget.widgets[2].node, 'mousedown', { shiftKey: true });
12531268
expect(widget.activeCellIndex).toBe(2);
12541269
expect(selected(widget)).toEqual([2, 3]);
1270+
1271+
// shift click deselect
1272+
simulate(widget.widgets[3].node, 'mousedown', { shiftKey: true });
1273+
expect(widget.activeCellIndex).toBe(3);
1274+
expect(selected(widget)).toEqual([]);
1275+
1276+
// shift click select by dragging from active cell
1277+
expect(widget.activeCellIndex).toBe(3);
1278+
simulate(widget.widgets[3].node, 'mousedown', { shiftKey: true });
1279+
expect(widget.activeCellIndex).toBe(3);
1280+
simulate(widget.widgets[4].node, 'mousemove', { shiftKey: true });
1281+
expect(selected(widget)).toEqual([3, 4]);
1282+
// test that selecting mode mouse up handler prevents default;
1283+
// in selecting mode we listen to the `mouseup` event to stop
1284+
// selecting when the mouse button gets released
1285+
const blockedMouseUpEvent = new MouseEvent('mouseup', {
1286+
bubbles: true,
1287+
cancelable: true
1288+
});
1289+
widget.widgets[4].node.dispatchEvent(blockedMouseUpEvent);
1290+
expect(blockedMouseUpEvent.defaultPrevented).toBe(true);
12551291
});
12561292

12571293
it('should not extend a selection if there is text selected in the output', () => {

0 commit comments

Comments
 (0)