Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 16 additions & 7 deletions packages/widgets/src/tabbar.ts
Original file line number Diff line number Diff line change
Expand Up @@ -618,6 +618,12 @@ export class TabBar<T> extends Widget {
case 'pointerdown':
this._evtPointerDown(event as PointerEvent);
break;
case 'mousedown':
// Keep the press visible to mouse-based listeners, but avoid focus changes.
if (this._dragData) {
event.preventDefault();
}
break;
case 'pointermove':
this._evtPointerMove(event as PointerEvent);
break;
Expand Down Expand Up @@ -650,6 +656,7 @@ export class TabBar<T> extends Widget {
*/
protected onBeforeAttach(msg: Message): void {
this.node.addEventListener('pointerdown', this);
this.node.addEventListener('mousedown', this);
this.node.addEventListener('pointerleave', this);
this.node.addEventListener('click', this);
this.node.addEventListener('dblclick', this);
Expand All @@ -661,6 +668,7 @@ export class TabBar<T> extends Widget {
*/
protected onAfterDetach(msg: Message): void {
this.node.removeEventListener('pointerdown', this);
this.node.removeEventListener('mousedown', this);
this.node.removeEventListener('pointerleave', this);
this.node.removeEventListener('click', this);
this.node.removeEventListener('dblclick', this);
Expand Down Expand Up @@ -952,11 +960,10 @@ export class TabBar<T> extends Widget {
: null;
let closeIconPressed = !!icon && icon.contains(event.target as HTMLElement);

// Pressing on a tab stops the event propagation.
if (!closeIconPressed || !Utils.isTouchEvent(event)) {
// Cancel touch compatibility events, but let mouse presses reach ancestors.
if (Utils.isTouchEvent(event) && !closeIconPressed) {
event.preventDefault();
}
event.stopPropagation();

// Initialize the non-measured parts of the drag data.
this._dragData = {
Expand Down Expand Up @@ -1115,11 +1122,13 @@ export class TabBar<T> extends Widget {

const isTouch = Utils.isTouchEvent(event);

// Stop the event propagation.
if (!isTouch) {
event.preventDefault();
// Suppress the release only when a tab is actually being dragged.
if (data.dragActive) {
if (!isTouch) {
event.preventDefault();
}
event.stopPropagation();
}
event.stopPropagation();

// Remove the extra mouse event listeners.
this.document.removeEventListener('pointermove', this, true);
Expand Down
64 changes: 64 additions & 0 deletions packages/widgets/tests/src/tabbar.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1481,6 +1481,38 @@ describe('@lumino/widgets', () => {
});

context('pointerdown', () => {
it('should let tab presses reach pointer and mouse listeners', () => {
let events: string[] = [];
let listener = (event: Event) => {
events.push(event.type);
};
document.body.addEventListener('pointerdown', listener);
document.body.addEventListener('mousedown', listener);
try {
let rect = tab.getBoundingClientRect();
let pointerDown = new PointerEvent('pointerdown', {
pointerType: 'mouse',
clientX: rect.left + 1,
clientY: rect.top + 1,
bubbles: true,
cancelable: true
});
tab.dispatchEvent(pointerDown);
expect(pointerDown.defaultPrevented).to.equal(false);
let mouseDown = new MouseEvent('mousedown', {
bubbles: true,
cancelable: true
});
tab.dispatchEvent(mouseDown);
expect(events).to.deep.equal(['pointerdown', 'mousedown']);
expect(mouseDown.defaultPrevented).to.equal(true);
} finally {
document.body.removeEventListener('pointerdown', listener);
document.body.removeEventListener('mousedown', listener);
bar.releaseMouse();
}
});

it('should add event listeners if the tabs are movable', () => {
simulateOnNode(tab, 'pointerdown');
document.body.dispatchEvent(new PointerEvent('pointermove'));
Expand Down Expand Up @@ -1650,6 +1682,38 @@ describe('@lumino/widgets', () => {
});

context('pointerup', () => {
it('should suppress release propagation during a tab drag', () => {
let called = false;
let listener = () => {
called = true;
};
document.body.addEventListener('pointerup', listener);
try {
startDrag(bar);
simulateOnNode(tab, 'pointerup');
expect(called).to.equal(false);
} finally {
document.body.removeEventListener('pointerup', listener);
bar.releaseMouse();
}
});

it('should let a simple tab release reach ancestor listeners', () => {
let called = false;
let listener = () => {
called = true;
};
document.body.addEventListener('pointerup', listener);
try {
simulateOnNode(tab, 'pointerdown');
simulateOnNode(tab, 'pointerup');
expect(called).to.equal(true);
} finally {
document.body.removeEventListener('pointerup', listener);
bar.releaseMouse();
}
});

it('should emit the `tabMoved` signal', done => {
startDrag(bar);
document.body.dispatchEvent(new PointerEvent('pointerup'));
Expand Down
Loading