Mercurial
comparison .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 |
comparison
equal
deleted
inserted
replaced
-1:000000000000 | 0:78edf6b517a0 |
---|---|
1 import { chrome, chrome_version, gecko, ie, mac, presto, safari, webkit } from "../util/browser.js" | |
2 import { e_preventDefault } from "../util/event.js" | |
3 | |
4 import { updateDisplaySimple } from "./update_display.js" | |
5 import { setScrollLeft, updateScrollTop } from "./scrolling.js" | |
6 | |
7 // Since the delta values reported on mouse wheel events are | |
8 // unstandardized between browsers and even browser versions, and | |
9 // generally horribly unpredictable, this code starts by measuring | |
10 // the scroll effect that the first few mouse wheel events have, | |
11 // and, from that, detects the way it can convert deltas to pixel | |
12 // offsets afterwards. | |
13 // | |
14 // The reason we want to know the amount a wheel event will scroll | |
15 // is that it gives us a chance to update the display before the | |
16 // actual scrolling happens, reducing flickering. | |
17 | |
18 let wheelSamples = 0, wheelPixelsPerUnit = null | |
19 // Fill in a browser-detected starting value on browsers where we | |
20 // know one. These don't have to be accurate -- the result of them | |
21 // being wrong would just be a slight flicker on the first wheel | |
22 // scroll (if it is large enough). | |
23 if (ie) wheelPixelsPerUnit = -.53 | |
24 else if (gecko) wheelPixelsPerUnit = 15 | |
25 else if (chrome) wheelPixelsPerUnit = -.7 | |
26 else if (safari) wheelPixelsPerUnit = -1/3 | |
27 | |
28 function wheelEventDelta(e) { | |
29 let dx = e.wheelDeltaX, dy = e.wheelDeltaY | |
30 if (dx == null && e.detail && e.axis == e.HORIZONTAL_AXIS) dx = e.detail | |
31 if (dy == null && e.detail && e.axis == e.VERTICAL_AXIS) dy = e.detail | |
32 else if (dy == null) dy = e.wheelDelta | |
33 return {x: dx, y: dy} | |
34 } | |
35 export function wheelEventPixels(e) { | |
36 let delta = wheelEventDelta(e) | |
37 delta.x *= wheelPixelsPerUnit | |
38 delta.y *= wheelPixelsPerUnit | |
39 return delta | |
40 } | |
41 | |
42 export function onScrollWheel(cm, e) { | |
43 // On Chrome 102, viewport updates somehow stop wheel-based | |
44 // scrolling. Turning off pointer events during the scroll seems | |
45 // to avoid the issue. | |
46 if (chrome && chrome_version == 102) { | |
47 if (cm.display.chromeScrollHack == null) cm.display.sizer.style.pointerEvents = "none" | |
48 else clearTimeout(cm.display.chromeScrollHack) | |
49 cm.display.chromeScrollHack = setTimeout(() => { | |
50 cm.display.chromeScrollHack = null | |
51 cm.display.sizer.style.pointerEvents = "" | |
52 }, 100) | |
53 } | |
54 let delta = wheelEventDelta(e), dx = delta.x, dy = delta.y | |
55 let pixelsPerUnit = wheelPixelsPerUnit | |
56 if (e.deltaMode === 0) { | |
57 dx = e.deltaX | |
58 dy = e.deltaY | |
59 pixelsPerUnit = 1 | |
60 } | |
61 | |
62 let display = cm.display, scroll = display.scroller | |
63 // Quit if there's nothing to scroll here | |
64 let canScrollX = scroll.scrollWidth > scroll.clientWidth | |
65 let canScrollY = scroll.scrollHeight > scroll.clientHeight | |
66 if (!(dx && canScrollX || dy && canScrollY)) return | |
67 | |
68 // Webkit browsers on OS X abort momentum scrolls when the target | |
69 // of the scroll event is removed from the scrollable element. | |
70 // This hack (see related code in patchDisplay) makes sure the | |
71 // element is kept around. | |
72 if (dy && mac && webkit) { | |
73 outer: for (let cur = e.target, view = display.view; cur != scroll; cur = cur.parentNode) { | |
74 for (let i = 0; i < view.length; i++) { | |
75 if (view[i].node == cur) { | |
76 cm.display.currentWheelTarget = cur | |
77 break outer | |
78 } | |
79 } | |
80 } | |
81 } | |
82 | |
83 // On some browsers, horizontal scrolling will cause redraws to | |
84 // happen before the gutter has been realigned, causing it to | |
85 // wriggle around in a most unseemly way. When we have an | |
86 // estimated pixels/delta value, we just handle horizontal | |
87 // scrolling entirely here. It'll be slightly off from native, but | |
88 // better than glitching out. | |
89 if (dx && !gecko && !presto && pixelsPerUnit != null) { | |
90 if (dy && canScrollY) | |
91 updateScrollTop(cm, Math.max(0, scroll.scrollTop + dy * pixelsPerUnit)) | |
92 setScrollLeft(cm, Math.max(0, scroll.scrollLeft + dx * pixelsPerUnit)) | |
93 // Only prevent default scrolling if vertical scrolling is | |
94 // actually possible. Otherwise, it causes vertical scroll | |
95 // jitter on OSX trackpads when deltaX is small and deltaY | |
96 // is large (issue #3579) | |
97 if (!dy || (dy && canScrollY)) | |
98 e_preventDefault(e) | |
99 display.wheelStartX = null // Abort measurement, if in progress | |
100 return | |
101 } | |
102 | |
103 // 'Project' the visible viewport to cover the area that is being | |
104 // scrolled into view (if we know enough to estimate it). | |
105 if (dy && pixelsPerUnit != null) { | |
106 let pixels = dy * pixelsPerUnit | |
107 let top = cm.doc.scrollTop, bot = top + display.wrapper.clientHeight | |
108 if (pixels < 0) top = Math.max(0, top + pixels - 50) | |
109 else bot = Math.min(cm.doc.height, bot + pixels + 50) | |
110 updateDisplaySimple(cm, {top: top, bottom: bot}) | |
111 } | |
112 | |
113 if (wheelSamples < 20 && e.deltaMode !== 0) { | |
114 if (display.wheelStartX == null) { | |
115 display.wheelStartX = scroll.scrollLeft; display.wheelStartY = scroll.scrollTop | |
116 display.wheelDX = dx; display.wheelDY = dy | |
117 setTimeout(() => { | |
118 if (display.wheelStartX == null) return | |
119 let movedX = scroll.scrollLeft - display.wheelStartX | |
120 let movedY = scroll.scrollTop - display.wheelStartY | |
121 let sample = (movedY && display.wheelDY && movedY / display.wheelDY) || | |
122 (movedX && display.wheelDX && movedX / display.wheelDX) | |
123 display.wheelStartX = display.wheelStartY = null | |
124 if (!sample) return | |
125 wheelPixelsPerUnit = (wheelPixelsPerUnit * wheelSamples + sample) / (wheelSamples + 1) | |
126 ++wheelSamples | |
127 }, 200) | |
128 } else { | |
129 display.wheelDX += dx; display.wheelDY += dy | |
130 } | |
131 } | |
132 } |