diff --git a/src/display/operations.js b/src/display/operations.js index e18fd084c9765feabd0519450f5cefa8478caba2..566eb5aa853b6991526c28550f3000456b9bb0e9 100644 --- a/src/display/operations.js +++ b/src/display/operations.js @@ -7,7 +7,7 @@ import { finishOperation, pushOperation } from "../util/operation_group" import { ensureFocus } from "./focus" import { measureForScrollbars, updateScrollbars } from "./scrollbars" -import { setScrollLeft } from "./scroll_events" +import { setScrollLeft, setScrollTop } from "./scroll_events" import { restartBlink } from "./selection" import { maybeScrollWindow, scrollPosIntoView } from "./scrolling" import { DisplayUpdate, maybeClipScrollbars, postUpdateDisplay, setDocumentHeight, updateDisplayIfNeeded } from "./update_display" @@ -141,11 +141,8 @@ function endOperation_finish(op) { display.wheelStartX = display.wheelStartY = null // Propagate the scroll position to the actual DOM scroller - if (op.scrollTop != null && (display.scroller.scrollTop != op.scrollTop || op.forceScroll)) { - doc.scrollTop = Math.max(0, Math.min(display.scroller.scrollHeight - display.scroller.clientHeight, op.scrollTop)) - display.scrollbars.setScrollTop(doc.scrollTop) - display.scroller.scrollTop = doc.scrollTop - } + if (op.scrollTop != null) setScrollTop(cm, op.scrollTop, true) + if (op.scrollLeft != null) setScrollLeft(cm, op.scrollLeft, true, true) // If we need to scroll a specific position into view, do so. if (op.scrollToPos) { diff --git a/src/display/scroll_events.js b/src/display/scroll_events.js index 38d91441c0a28f8c079b33b5d934c22820073d0e..b7ce0f583d3422192ade04a93c759f1c04108a52 100644 --- a/src/display/scroll_events.js +++ b/src/display/scroll_events.js @@ -7,15 +7,21 @@ import { updateDisplaySimple} from "./update_display" // Sync the scrollable area and scrollbars, ensure the viewport // covers the visible area. -export function setScrollTop(cm, val) { +export function updateScrollTop(cm, val) { if (Math.abs(cm.doc.scrollTop - val) < 2) return - cm.doc.scrollTop = val if (!gecko) updateDisplaySimple(cm, {top: val}) - if (cm.display.scroller.scrollTop != val) cm.display.scroller.scrollTop = val - cm.display.scrollbars.setScrollTop(val) + setScrollTop(cm, val) if (gecko) updateDisplaySimple(cm) startWorker(cm, 100) } +export function setScrollTop(cm, val, forceScroll) { + val = Math.min(cm.display.scroller.scrollHeight - cm.display.scroller.clientHeight, val) + if (cm.display.scroller.scrollTop == val && !forceScroll) return + cm.doc.scrollTop = val + cm.display.scrollbars.setScrollTop(val) + cm.display.scroller.scrollTop = val +} + // Sync scroller and scrollbar, ensure the gutter elements are // aligned. export function setScrollLeft(cm, val, isScroller, forceScroll) { @@ -94,7 +100,7 @@ export function onScrollWheel(cm, e) { // better than glitching out. if (dx && !gecko && !presto && wheelPixelsPerUnit != null) { if (dy && canScrollY) - setScrollTop(cm, Math.max(0, Math.min(scroll.scrollTop + dy * wheelPixelsPerUnit, scroll.scrollHeight - scroll.clientHeight))) + updateScrollTop(cm, Math.max(0, scroll.scrollTop + dy * wheelPixelsPerUnit)) setScrollLeft(cm, Math.max(0, Math.min(scroll.scrollLeft + dx * wheelPixelsPerUnit, scroll.scrollWidth - scroll.clientWidth))) // Only prevent default scrolling if vertical scrolling is // actually possible. Otherwise, it causes vertical scroll diff --git a/src/display/scrollbars.js b/src/display/scrollbars.js index af31c78140180b11e45ff77472bba7ed9bd31461..d2f73c9154ebe10655075e78abab6483c595d880 100644 --- a/src/display/scrollbars.js +++ b/src/display/scrollbars.js @@ -5,7 +5,7 @@ import { ie, ie_version, mac, mac_geMountainLion } from "../util/browser" import { updateHeightsInViewport } from "./update_lines" import { Delayed } from "../util/misc" -import { setScrollLeft, setScrollTop } from "./scroll_events" +import { setScrollLeft, updateScrollTop } from "./scroll_events" // SCROLLBARS @@ -185,7 +185,7 @@ export function initScrollbars(cm) { node.setAttribute("cm-not-content", "true") }, (pos, axis) => { if (axis == "horizontal") setScrollLeft(cm, pos) - else setScrollTop(cm, pos) + else updateScrollTop(cm, pos) }, cm) if (cm.display.scrollbars.addClass) addClass(cm.display.wrapper, cm.display.scrollbars.addClass) diff --git a/src/display/scrolling.js b/src/display/scrolling.js index b2deb2ed6444d56b5ac35c2fb4cae95b083fca51..5d06a63b500a375da0e739feddd2bf1fee472951 100644 --- a/src/display/scrolling.js +++ b/src/display/scrolling.js @@ -4,7 +4,7 @@ import { phantom } from "../util/browser" import { elt } from "../util/dom" import { signalDOMEvent } from "../util/event" -import { setScrollLeft, setScrollTop } from "./scroll_events" +import { setScrollLeft, updateScrollTop } from "./scroll_events" // SCROLLING THINGS INTO VIEW @@ -44,7 +44,7 @@ export function scrollPosIntoView(cm, pos, end, margin) { let scrollPos = calculateScrollPos(cm, rect) let startTop = cm.doc.scrollTop, startLeft = cm.doc.scrollLeft if (scrollPos.scrollTop != null) { - setScrollTop(cm, scrollPos.scrollTop) + updateScrollTop(cm, scrollPos.scrollTop) if (Math.abs(cm.doc.scrollTop - startTop) > 1) changed = true } if (scrollPos.scrollLeft != null) { @@ -59,7 +59,7 @@ export function scrollPosIntoView(cm, pos, end, margin) { // Scroll a given set of coordinates into view (immediately). export function scrollIntoView(cm, rect) { let scrollPos = calculateScrollPos(cm, rect) - if (scrollPos.scrollTop != null) setScrollTop(cm, scrollPos.scrollTop) + if (scrollPos.scrollTop != null) updateScrollTop(cm, scrollPos.scrollTop) if (scrollPos.scrollLeft != null) setScrollLeft(cm, scrollPos.scrollLeft) } diff --git a/src/edit/CodeMirror.js b/src/edit/CodeMirror.js index 2d502c9ebc6f5a0c5a4f3ef8ebc56ddbb98788ca..5f66c9f4f715a6b3ca0b9312889fc117d554bb52 100644 --- a/src/edit/CodeMirror.js +++ b/src/edit/CodeMirror.js @@ -4,7 +4,7 @@ import { setGuttersForLineNumbers, updateGutters } from "../display/gutters" import { maybeUpdateLineNumberWidth } from "../display/line_numbers" import { endOperation, operation, startOperation } from "../display/operations" import { initScrollbars } from "../display/scrollbars" -import { onScrollWheel, setScrollLeft, setScrollTop } from "../display/scroll_events" +import { onScrollWheel, setScrollLeft, updateScrollTop } from "../display/scroll_events" import { clipPos, Pos } from "../line/pos" import { posFromMouse } from "../measurement/position_measurement" import { eventInWidget } from "../measurement/widgets" @@ -180,7 +180,7 @@ function registerEventHandlers(cm) { // area, ensure viewport is updated when scrolling. on(d.scroller, "scroll", () => { if (d.scroller.clientHeight) { - setScrollTop(cm, d.scroller.scrollTop) + updateScrollTop(cm, d.scroller.scrollTop) setScrollLeft(cm, d.scroller.scrollLeft, true) signal(cm, "scroll", cm) }