diff --git a/src/dom.ts b/src/dom.ts index 8812454..f3ea4d1 100644 --- a/src/dom.ts +++ b/src/dom.ts @@ -208,13 +208,14 @@ export function scrollRectIntoView(dom: HTMLElement, rect: Rect, side: -1 | 1, } } -export function scrollableParent(dom: HTMLElement) { - let doc = dom.ownerDocument +export function scrollableParents(dom: HTMLElement) { + let doc = dom.ownerDocument, x: HTMLElement | undefined, y: HTMLElement | undefined for (let cur = dom.parentNode as HTMLElement | null; cur;) { - if (cur == doc.body) { + if (cur == doc.body || (x && y)) { break } else if (cur.nodeType == 1) { - if (cur.scrollHeight > cur.clientHeight || cur.scrollWidth > cur.clientWidth) return cur + if (!y && cur.scrollHeight > cur.clientHeight) y = cur + if (!x && cur.scrollWidth > cur.clientWidth) x = cur cur = cur.assignedSlot || cur.parentNode as HTMLElement | null } else if (cur.nodeType == 11) { cur = (cur as any).host @@ -222,7 +223,7 @@ export function scrollableParent(dom: HTMLElement) { break } } - return null + return {x, y} } export interface SelectionRange { diff --git a/src/input.ts b/src/input.ts index a4c9288..2734be6 100644 --- a/src/input.ts +++ b/src/input.ts @@ -6,7 +6,7 @@ import {ViewUpdate, PluginValue, clickAddsSelectionRange, dragMovesSelection as logException, mouseSelectionStyle, PluginInstance, focusChangeEffect, getScrollMargins} from "./extension" import browser from "./browser" import {groupAt, skipAtomicRanges} from "./cursor" -import {getSelection, focusPreventScroll, Rect, dispatchKey, scrollableParent} from "./dom" +import {getSelection, focusPreventScroll, Rect, dispatchKey, scrollableParents} from "./dom" // This will also be where dragging info and such goes export class InputState { @@ -287,7 +287,7 @@ class MouseSelection { extend: boolean multiple: boolean lastEvent: MouseEvent - scrollParent: HTMLElement | null + scrollParents: {x?: HTMLElement, y?: HTMLElement} scrollSpeed = {x: 0, y: 0} scrolling = -1 atoms: readonly RangeSet[] @@ -297,7 +297,7 @@ class MouseSelection { private style: MouseSelectionStyle, private mustSelect: boolean) { this.lastEvent = startEvent - this.scrollParent = scrollableParent(view.contentDOM) + this.scrollParents = scrollableParents(view.contentDOM) this.atoms = view.state.facet(atomicRanges).map(f => f(view)) let doc = view.contentDOM.ownerDocument! doc.addEventListener("mousemove", this.move = this.move.bind(this)) @@ -320,18 +320,19 @@ class MouseSelection { this.select(this.lastEvent = event) let sx = 0, sy = 0 - let rect = this.scrollParent?.getBoundingClientRect() - || {left: 0, top: 0, right: this.view.win.innerWidth, bottom: this.view.win.innerHeight} + let left = 0, top = 0, right = this.view.win.innerWidth, bottom = this.view.win.innerHeight + if (this.scrollParents.x) ({left, right} = this.scrollParents.x.getBoundingClientRect()) + if (this.scrollParents.y) ({top, bottom} = this.scrollParents.y.getBoundingClientRect()) let margins = getScrollMargins(this.view) - if (event.clientX - margins.left <= rect.left + dragScrollMargin) - sx = -dragScrollSpeed(rect.left - event.clientX) - else if (event.clientX + margins.right >= rect.right - dragScrollMargin) - sx = dragScrollSpeed(event.clientX - rect.right) - if (event.clientY - margins.top <= rect.top + dragScrollMargin) - sy = -dragScrollSpeed(rect.top - event.clientY) - else if (event.clientY + margins.bottom >= rect.bottom - dragScrollMargin) - sy = dragScrollSpeed(event.clientY - rect.bottom) + if (event.clientX - margins.left <= left + dragScrollMargin) + sx = -dragScrollSpeed(left - event.clientX) + else if (event.clientX + margins.right >= right - dragScrollMargin) + sx = dragScrollSpeed(event.clientX - right) + if (event.clientY - margins.top <= top + dragScrollMargin) + sy = -dragScrollSpeed(top - event.clientY) + else if (event.clientY + margins.bottom >= bottom - dragScrollMargin) + sy = dragScrollSpeed(event.clientY - bottom) this.setScrollSpeed(sx, sy) } @@ -360,12 +361,16 @@ class MouseSelection { } scroll() { - if (this.scrollParent) { - this.scrollParent.scrollLeft += this.scrollSpeed.x - this.scrollParent.scrollTop += this.scrollSpeed.y - } else { - this.view.win.scrollBy(this.scrollSpeed.x, this.scrollSpeed.y) + let {x, y} = this.scrollSpeed + if (x && this.scrollParents.x) { + this.scrollParents.x.scrollLeft += x + x = 0 } + if (y && this.scrollParents.y) { + this.scrollParents.y.scrollTop += y + y = 0 + } + if (x || y) this.view.win.scrollBy(x, y) if (this.dragging === false) this.select(this.lastEvent) }