Skip to content

Commit

Permalink
Yet another attempt at feature-detecting wheel delta values
Browse files Browse the repository at this point in the history
Removes the kludge with the vertical scrollbar trying to handle
all wheel events.

Issue #810
  • Loading branch information
marijnh committed Oct 16, 2012
1 parent b17c3cf commit fbee3d8
Showing 1 changed file with 68 additions and 50 deletions.
118 changes: 68 additions & 50 deletions lib/codemirror.js
Original file line number Diff line number Diff line change
Expand Up @@ -1103,63 +1103,19 @@ window.CodeMirror = (function() {
if (!gecko) on(d.scroller, "contextmenu", function(e) {onContextMenu(cm, e);});

on(d.scroller, "scroll", function() {
if (d.scroller.scrollTop != cm.view.scrollTop) {
updateDisplay(cm, [], cm.view.scrollTop = d.scroller.scrollTop);
d.scrollbarV.scrollTop = cm.view.scrollTop;
}
if (d.scroller.scrollLeft != cm.view.scrollLeft) {
d.scrollbarH.scrollLeft = cm.view.scrollLeft = d.scroller.scrollLeft;
alignVertically(cm.display);
}
setScrollTop(cm, d.scroller.scrollTop);
setScrollLeft(cm, d.scroller.scrollLeft);
signal(cm, "scroll", cm);
});
on(d.scrollbarV, "scroll", function() {
if (d.scrollbarV.scrollTop != cm.view.scrollTop) {
updateDisplay(cm, [], cm.view.scrollTop = d.scrollbarV.scrollTop);
d.scroller.scrollTop = cm.view.scrollTop;
}
if (d.scrollbarV.style.overflowX && d.scrollbarV.scrollLeft != cm.view.scrollLeft) {
d.scroller.scrollLeft = cm.view.scrollLeft = d.scrollbarV.scrollLeft;
alignVertically(cm.display);
}
setScrollTop(cm, d.scrollbarV.scrollTop);
});
on(d.scrollbarH, "scroll", function() {
if (d.scrollbarH.scrollLeft != cm.view.scrollLeft) {
d.scroller.scrollLeft = cm.view.scrollLeft = d.scrollbarH.scrollLeft;
alignVertically(cm.display);
}
setScrollLeft(cm, d.scrollbarH.scrollLeft);
});

// Kludge to prevent long wheel scrolls from causing flicker -- if
// they scroll the scroller div directly, we won't have a chance
// to update the content before the scroll takes place, which may
// cause blank screen area to come into view. This makes sure the
// vertical scrollbar grows to fill the whole editor during a
// wheel scroll.
var scrollbarReset = new Delayed(), active = false;
function growScrollbarV() {
var bar = d.scrollbarV;
if (!active) {
active = true;
if (bar.style.display == "none") return;
bar.style.left = d.gutters.offsetWidth + "px";
if (d.scrollbarH.style.display == "block") {
bar.firstChild.style.width = (d.scroller.scrollWidth - d.scroller.clientWidth + bar.clientWidth) + "px";
bar.scrollLeft = d.scrollbarH.scrollLeft;
bar.style.marginBottom = (-scrollbarWidth(d.measure)) + "px";
bar.style.overflowX = "scroll";
}
}
scrollbarReset.set(150, function() {
bar.style.left = bar.style.overflowX =
bar.firstChild.style.width = bar.style.marginBottom = "";
active = false;
});
}
on(d.scroller, "mousewheel", growScrollbarV);
on(d.scrollbarV, "mousewheel", growScrollbarV);
on(d.scroller, "DOMMouseScroll", growScrollbarV);
on(d.scrollbarV, "DOMMouseScroll", growScrollbarV);
on(d.scroller, "mousewheel", function(e){onScrollWheel(cm, e);});
on(d.scroller, "DOMMouseScroll", function(e){onScrollWheel(cm, e);});

function reFocus() { if (cm.view.focused) setTimeout(bind(focusInput, cm), 0); }
on(d.scrollbarH, "mousedown", reFocus);
Expand Down Expand Up @@ -1454,6 +1410,68 @@ window.CodeMirror = (function() {
e.dataTransfer.setDragImage(elt('img'), 0, 0);
}

function setScrollTop(cm, val) {
if (cm.view.scrollTop == val) return;
cm.view.scrollTop = val;
if (!gecko) updateDisplay(cm, [], val);
if (cm.display.scroller.scrollTop != val) cm.display.scroller.scrollTop = val;
if (cm.display.scrollbarV.scrollTop != val) cm.display.scrollbarV.scrollTop = val;
if (gecko) updateDisplay(cm, []);
}
function setScrollLeft(cm, val) {
if (cm.view.scrollLeft == val) return;
cm.view.scrollLeft = val;
if (cm.display.scroller.scrollLeft != val) cm.display.scroller.scrollLeft = val;
if (cm.display.scrollbarH.scrollLeft != val) cm.display.scrollbarH.scrollLeft = val;
alignVertically(cm.display);
}

// 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 directly handle the wheel event is that it
// gives us a chance to update the display before the actual
// scrolling happens, reducing flickering.

var wheelSamples = [], wheelDX, wheelDY, wheelStartX, wheelStartY, wheelPixelsPerUnit;
function onScrollWheel(cm, e) {
var 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;

var scroll = cm.display.scroller;
if (wheelPixelsPerUnit != null) {
if (dx) setScrollLeft(cm, Math.max(0, Math.round(scroll.scrollLeft += dx * wheelPixelsPerUnit)));
if (dy) setScrollTop(cm, Math.max(0, Math.round(scroll.scrollTop + dy * wheelPixelsPerUnit)));
e_stop(e);
} else {
if (wheelStartX == null) {
wheelStartX = scroll.scrollLeft; wheelStartY = scroll.scrollTop;
wheelDX = dx; wheelDY = dy;
setTimeout(function() {
var movedX = scroll.scrollLeft - wheelStartX;
var movedY = scroll.scrollTop - wheelStartY;
var sample = (movedY && wheelDY && movedY / wheelDY) ||
(movedX && wheelDX && movedX / wheelDX);
wheelStartX = wheelStartY = null;
if (!sample) return;
wheelSamples.push(sample);
if (wheelSamples.length >= 15) {
for (var total = 0, i = 0; i < wheelSamples.length; ++i) total += wheelSamples[i];
wheelPixelsPerUnit = total / wheelSamples.length;
}
}, 200);
} else {
wheelDX += dx; wheelDY += dy;
}
}
}

function doHandleBinding(cm, bound, dropShift) {
if (typeof bound == "string") {
bound = commands[bound];
Expand Down

0 comments on commit fbee3d8

Please sign in to comment.