(cm, e)
| 2862 | else if (safari) wheelPixelsPerUnit = -1/3; |
| 2863 | |
| 2864 | function onScrollWheel(cm, e) { |
| 2865 | var dx = e.wheelDeltaX, dy = e.wheelDeltaY; |
| 2866 | if (dx == null && e.detail && e.axis == e.HORIZONTAL_AXIS) dx = e.detail; |
| 2867 | if (dy == null && e.detail && e.axis == e.VERTICAL_AXIS) dy = e.detail; |
| 2868 | else if (dy == null) dy = e.wheelDelta; |
| 2869 | |
| 2870 | var display = cm.display, scroll = display.scroller; |
| 2871 | // Quit if there's nothing to scroll here |
| 2872 | if (!(dx && scroll.scrollWidth > scroll.clientWidth || |
| 2873 | dy && scroll.scrollHeight > scroll.clientHeight)) return; |
| 2874 | |
| 2875 | // Webkit browsers on OS X abort momentum scrolls when the target |
| 2876 | // of the scroll event is removed from the scrollable element. |
| 2877 | // This hack (see related code in patchDisplay) makes sure the |
| 2878 | // element is kept around. |
| 2879 | if (dy && mac && webkit) { |
| 2880 | outer: for (var cur = e.target, view = display.view; cur != scroll; cur = cur.parentNode) { |
| 2881 | for (var i = 0; i < view.length; i++) { |
| 2882 | if (view[i].node == cur) { |
| 2883 | cm.display.currentWheelTarget = cur; |
| 2884 | break outer; |
| 2885 | } |
| 2886 | } |
| 2887 | } |
| 2888 | } |
| 2889 | |
| 2890 | // On some browsers, horizontal scrolling will cause redraws to |
| 2891 | // happen before the gutter has been realigned, causing it to |
| 2892 | // wriggle around in a most unseemly way. When we have an |
| 2893 | // estimated pixels/delta value, we just handle horizontal |
| 2894 | // scrolling entirely here. It'll be slightly off from native, but |
| 2895 | // better than glitching out. |
| 2896 | if (dx && !gecko && !presto && wheelPixelsPerUnit != null) { |
| 2897 | if (dy) |
| 2898 | setScrollTop(cm, Math.max(0, Math.min(scroll.scrollTop + dy * wheelPixelsPerUnit, scroll.scrollHeight - scroll.clientHeight))); |
| 2899 | setScrollLeft(cm, Math.max(0, Math.min(scroll.scrollLeft + dx * wheelPixelsPerUnit, scroll.scrollWidth - scroll.clientWidth))); |
| 2900 | e_preventDefault(e); |
| 2901 | display.wheelStartX = null; // Abort measurement, if in progress |
| 2902 | return; |
| 2903 | } |
| 2904 | |
| 2905 | // 'Project' the visible viewport to cover the area that is being |
| 2906 | // scrolled into view (if we know enough to estimate it). |
| 2907 | if (dy && wheelPixelsPerUnit != null) { |
| 2908 | var pixels = dy * wheelPixelsPerUnit; |
| 2909 | var top = cm.doc.scrollTop, bot = top + display.wrapper.clientHeight; |
| 2910 | if (pixels < 0) top = Math.max(0, top + pixels - 50); |
| 2911 | else bot = Math.min(cm.doc.height, bot + pixels + 50); |
| 2912 | updateDisplay(cm, {top: top, bottom: bot}); |
| 2913 | } |
| 2914 | |
| 2915 | if (wheelSamples < 20) { |
| 2916 | if (display.wheelStartX == null) { |
| 2917 | display.wheelStartX = scroll.scrollLeft; display.wheelStartY = scroll.scrollTop; |
| 2918 | display.wheelDX = dx; display.wheelDY = dy; |
| 2919 | setTimeout(function() { |
| 2920 | if (display.wheelStartX == null) return; |
| 2921 | var movedX = scroll.scrollLeft - display.wheelStartX; |
no test coverage detected