diff .cms/lib/codemirror/src/display/scroll_events.js @ 0:78edf6b517a0 draft

24.10
author Coffee CMS <info@coffee-cms.ru>
date Fri, 11 Oct 2024 22:40:23 +0000
parents
children
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/.cms/lib/codemirror/src/display/scroll_events.js	Fri Oct 11 22:40:23 2024 +0000
@@ -0,0 +1,132 @@
+import { chrome, chrome_version, gecko, ie, mac, presto, safari, webkit } from "../util/browser.js"
+import { e_preventDefault } from "../util/event.js"
+
+import { updateDisplaySimple } from "./update_display.js"
+import { setScrollLeft, updateScrollTop } from "./scrolling.js"
+
+// Since the delta values reported on mouse wheel events are
+// unstandardized between browsers and even browser versions, and
+// generally horribly unpredictable, this code starts by measuring
+// the scroll effect that the first few mouse wheel events have,
+// and, from that, detects the way it can convert deltas to pixel
+// offsets afterwards.
+//
+// The reason we want to know the amount a wheel event will scroll
+// is that it gives us a chance to update the display before the
+// actual scrolling happens, reducing flickering.
+
+let wheelSamples = 0, wheelPixelsPerUnit = null
+// Fill in a browser-detected starting value on browsers where we
+// know one. These don't have to be accurate -- the result of them
+// being wrong would just be a slight flicker on the first wheel
+// scroll (if it is large enough).
+if (ie) wheelPixelsPerUnit = -.53
+else if (gecko) wheelPixelsPerUnit = 15
+else if (chrome) wheelPixelsPerUnit = -.7
+else if (safari) wheelPixelsPerUnit = -1/3
+
+function wheelEventDelta(e) {
+  let dx = e.wheelDeltaX, dy = e.wheelDeltaY
+  if (dx == null && e.detail && e.axis == e.HORIZONTAL_AXIS) dx = e.detail
+  if (dy == null && e.detail && e.axis == e.VERTICAL_AXIS) dy = e.detail
+  else if (dy == null) dy = e.wheelDelta
+  return {x: dx, y: dy}
+}
+export function wheelEventPixels(e) {
+  let delta = wheelEventDelta(e)
+  delta.x *= wheelPixelsPerUnit
+  delta.y *= wheelPixelsPerUnit
+  return delta
+}
+
+export function onScrollWheel(cm, e) {
+  // On Chrome 102, viewport updates somehow stop wheel-based
+  // scrolling. Turning off pointer events during the scroll seems
+  // to avoid the issue.
+  if (chrome && chrome_version == 102) {
+    if (cm.display.chromeScrollHack == null) cm.display.sizer.style.pointerEvents = "none"
+    else clearTimeout(cm.display.chromeScrollHack)
+    cm.display.chromeScrollHack = setTimeout(() => {
+      cm.display.chromeScrollHack = null
+      cm.display.sizer.style.pointerEvents = ""
+    }, 100)
+  }
+  let delta = wheelEventDelta(e), dx = delta.x, dy = delta.y
+  let pixelsPerUnit = wheelPixelsPerUnit
+  if (e.deltaMode === 0) {
+    dx = e.deltaX
+    dy = e.deltaY
+    pixelsPerUnit = 1
+  }
+
+  let display = cm.display, scroll = display.scroller
+  // Quit if there's nothing to scroll here
+  let canScrollX = scroll.scrollWidth > scroll.clientWidth
+  let canScrollY = scroll.scrollHeight > scroll.clientHeight
+  if (!(dx && canScrollX || dy && canScrollY)) return
+
+  // Webkit browsers on OS X abort momentum scrolls when the target
+  // of the scroll event is removed from the scrollable element.
+  // This hack (see related code in patchDisplay) makes sure the
+  // element is kept around.
+  if (dy && mac && webkit) {
+    outer: for (let cur = e.target, view = display.view; cur != scroll; cur = cur.parentNode) {
+      for (let i = 0; i < view.length; i++) {
+        if (view[i].node == cur) {
+          cm.display.currentWheelTarget = cur
+          break outer
+        }
+      }
+    }
+  }
+
+  // On some browsers, horizontal scrolling will cause redraws to
+  // happen before the gutter has been realigned, causing it to
+  // wriggle around in a most unseemly way. When we have an
+  // estimated pixels/delta value, we just handle horizontal
+  // scrolling entirely here. It'll be slightly off from native, but
+  // better than glitching out.
+  if (dx && !gecko && !presto && pixelsPerUnit != null) {
+    if (dy && canScrollY)
+      updateScrollTop(cm, Math.max(0, scroll.scrollTop + dy * pixelsPerUnit))
+    setScrollLeft(cm, Math.max(0, scroll.scrollLeft + dx * pixelsPerUnit))
+    // Only prevent default scrolling if vertical scrolling is
+    // actually possible. Otherwise, it causes vertical scroll
+    // jitter on OSX trackpads when deltaX is small and deltaY
+    // is large (issue #3579)
+    if (!dy || (dy && canScrollY))
+      e_preventDefault(e)
+    display.wheelStartX = null // Abort measurement, if in progress
+    return
+  }
+
+  // 'Project' the visible viewport to cover the area that is being
+  // scrolled into view (if we know enough to estimate it).
+  if (dy && pixelsPerUnit != null) {
+    let pixels = dy * pixelsPerUnit
+    let top = cm.doc.scrollTop, bot = top + display.wrapper.clientHeight
+    if (pixels < 0) top = Math.max(0, top + pixels - 50)
+    else bot = Math.min(cm.doc.height, bot + pixels + 50)
+    updateDisplaySimple(cm, {top: top, bottom: bot})
+  }
+
+  if (wheelSamples < 20 && e.deltaMode !== 0) {
+    if (display.wheelStartX == null) {
+      display.wheelStartX = scroll.scrollLeft; display.wheelStartY = scroll.scrollTop
+      display.wheelDX = dx; display.wheelDY = dy
+      setTimeout(() => {
+        if (display.wheelStartX == null) return
+        let movedX = scroll.scrollLeft - display.wheelStartX
+        let movedY = scroll.scrollTop - display.wheelStartY
+        let sample = (movedY && display.wheelDY && movedY / display.wheelDY) ||
+          (movedX && display.wheelDX && movedX / display.wheelDX)
+        display.wheelStartX = display.wheelStartY = null
+        if (!sample) return
+        wheelPixelsPerUnit = (wheelPixelsPerUnit * wheelSamples + sample) / (wheelSamples + 1)
+        ++wheelSamples
+      }, 200)
+    } else {
+      display.wheelDX += dx; display.wheelDY += dy
+    }
+  }
+}