diff --git a/src/Terminal.ts b/src/Terminal.ts index 6d23e16c..10094200 100644 --- a/src/Terminal.ts +++ b/src/Terminal.ts @@ -1037,8 +1037,9 @@ export class Terminal extends Disposable implements ITerminal, IDisposable, IInp // the shell for example this.register(addDisposableDomListener(el, 'wheel', (ev: WheelEvent) => { if (this.mouseEvents) return; - this.viewport.onWheel(ev); - return this.cancel(ev); + if (!this.viewport.onWheel(ev)) { + return this.cancel(ev); + } })); this.register(addDisposableDomListener(el, 'touchstart', (ev: TouchEvent) => { @@ -1049,8 +1050,9 @@ export class Terminal extends Disposable implements ITerminal, IDisposable, IInp this.register(addDisposableDomListener(el, 'touchmove', (ev: TouchEvent) => { if (this.mouseEvents) return; - this.viewport.onTouchMove(ev); - return this.cancel(ev); + if (!this.viewport.onTouchMove(ev)) { + return this.cancel(ev); + } })); } diff --git a/src/TestUtils.test.ts b/src/TestUtils.test.ts index 0ee948d5..4a8e98d6 100644 --- a/src/TestUtils.test.ts +++ b/src/TestUtils.test.ts @@ -401,13 +401,13 @@ export class MockViewport implements IViewport { onThemeChange(colors: IColorSet): void { throw new Error('Method not implemented.'); } - onWheel(ev: WheelEvent): void { + onWheel(ev: WheelEvent): boolean { throw new Error('Method not implemented.'); } onTouchStart(ev: TouchEvent): void { throw new Error('Method not implemented.'); } - onTouchMove(ev: TouchEvent): void { + onTouchMove(ev: TouchEvent): boolean { throw new Error('Method not implemented.'); } syncScrollArea(): void { } diff --git a/src/browser/Types.d.ts b/src/browser/Types.d.ts index 3f3a7637..894beb36 100644 --- a/src/browser/Types.d.ts +++ b/src/browser/Types.d.ts @@ -37,9 +37,9 @@ export interface IViewport extends IDisposable { scrollBarWidth: number; syncScrollArea(): void; getLinesScrolled(ev: WheelEvent): number; - onWheel(ev: WheelEvent): void; + onWheel(ev: WheelEvent): boolean; onTouchStart(ev: TouchEvent): void; - onTouchMove(ev: TouchEvent): void; + onTouchMove(ev: TouchEvent): boolean; onThemeChange(colors: IColorSet): void; } diff --git a/src/browser/Viewport.ts b/src/browser/Viewport.ts index 9625588d..96ee9621 100644 --- a/src/browser/Viewport.ts +++ b/src/browser/Viewport.ts @@ -152,20 +152,34 @@ export class Viewport extends Disposable implements IViewport { this._scrollLines(diff, true); } + + private _bubbleScroll(amount: number): boolean { + const scrollPosFromTop = this._viewportElement.scrollTop + this._lastRecordedViewportHeight; + if ((amount < 0 && this._viewportElement.scrollTop !== 0) || + (amount > 0 && scrollPosFromTop < this._lastRecordedBufferHeight)) { + return false; + } + return true; + } + /** * Handles mouse wheel events by adjusting the viewport's scrollTop and delegating the actual * scrolling to `onScroll`, this event needs to be attached manually by the consumer of * `Viewport`. * @param ev The mouse wheel event. */ - public onWheel(ev: WheelEvent): void { + public onWheel(ev: WheelEvent): boolean { const amount = this._getPixelsScrolled(ev); if (amount === 0) { - return; + return false; } this._viewportElement.scrollTop += amount; // Prevent the page from scrolling when the terminal scrolls - ev.preventDefault(); + const shouldBubbleEvent = this._bubbleScroll(amount); + if (!shouldBubbleEvent && ev.cancelable) { + ev.preventDefault(); + } + return shouldBubbleEvent; } private _getPixelsScrolled(ev: WheelEvent): number { @@ -220,13 +234,17 @@ export class Viewport extends Disposable implements IViewport { * Handles the touchmove event, scrolling the viewport if the position shifted. * @param ev The touch event. */ - public onTouchMove(ev: TouchEvent): void { + public onTouchMove(ev: TouchEvent): boolean { const deltaY = this._lastTouchY - ev.touches[0].pageY; this._lastTouchY = ev.touches[0].pageY; if (deltaY === 0) { - return; + return false; } this._viewportElement.scrollTop += deltaY; - ev.preventDefault(); + const shouldBubbleEvent = this._bubbleScroll(deltaY); + if (!shouldBubbleEvent && ev.cancelable) { + ev.preventDefault(); + } + return shouldBubbleEvent; } }