aboutsummaryrefslogtreecommitdiffstats
path: root/content_scripts
diff options
context:
space:
mode:
authorStephen Blott2014-11-11 13:31:00 +0000
committerStephen Blott2014-11-11 13:31:00 +0000
commitedc80d03200ecec78f7c30e7c8b0eb41b545cc55 (patch)
tree4a4c54f4b933bd3f2275b205dce3c8693172c41e /content_scripts
parent6bd7add111cbc3a643c786db2ba18c01c886eb97 (diff)
downloadvimium-edc80d03200ecec78f7c30e7c8b0eb41b545cc55.tar.bz2
Smooth scroll; eliminate race condition.
Diffstat (limited to 'content_scripts')
-rw-r--r--content_scripts/scroller.coffee43
1 files changed, 21 insertions, 22 deletions
diff --git a/content_scripts/scroller.coffee b/content_scripts/scroller.coffee
index fc4b922e..03be9694 100644
--- a/content_scripts/scroller.coffee
+++ b/content_scripts/scroller.coffee
@@ -77,37 +77,38 @@ performScroll = (element, axisName, amount, checkVisibility = true) ->
# Return the amount by which the scroll position has changed.
element[axisName] - before
+# How scrolling is handled:
+# - For non-smooth scrolling, the entire scroll happens immediately.
+# - For smooth scrolling with distinct key presses, a separate animator is initiated for each key press.
+# Therefore, several animators may be active at the same time. This ensures that two quick taps on `j`
+# scroll to (roughly) the same position as two slower taps.
+# - For smooth scrolling with keyboard repeat, the most recently-activated animator continues scrolling
+# until its corresponding keyup event is received. We never initiate a new animator on keyboard repeat.
+
# Scroll by a relative amount (a number) in some direction, possibly smoothly.
doScrollBy = do ->
time = 0
- lastActivationId = -1
- keyupHandler = null
-
- # When the keyboard is repeating and then the key is released, sometimes the last key event is delivered
- # *after* the keyup event. This could cause indefinite scrolling with no key pressed, because no further
- # keyup event is delivered (so we behave as if the key is still pressed). To get around this, we briefly
- # hold a lock; this prevents a new smooth scrolling event from starting too soon after the end of the
- # previous one.
- smoothScrollLock = false
+ mostRecentActivationId = -1
+ lastEvent = null
+ keyHandler = null
(element, direction, amount, wantSmooth) ->
+ if not keyHandler
+ keyHandler = root.handlerStack.push
+ keydown: (event) -> lastEvent = event
+ keyup: -> time += 1
+
axisName = scrollProperties[direction].axisName
unless wantSmooth and settings.get "smoothScroll"
return performScroll element, axisName, amount
- if lastActivationId == time or smoothScrollLock
- # This is a keyboard repeat (and the most-recently activated animator -- which is still active -- will
- # keep going), or it's too soon to begin smooth scrolling again.
+ if mostRecentActivationId == time or lastEvent?.repeat
+ # Either the most-recently activated animator has not yet received its keyup event (so it's still
+ # scrolling), or this is a keyboard repeat (for which we don't initiate a new animator).
return
- if not keyupHandler
- keyupHandler = root.handlerStack.push keyup: ->
- time += 1
- setTimeout((-> smoothScrollLock = false), 50)
- smoothScrollLock = true # Hereby also returning true, so allowing further propagation of the event.
-
- lastActivationId = activationId = ++time
+ mostRecentActivationId = activationId = ++time
duration = 100 # Duration in ms.
fudgeFactor = 25
@@ -126,7 +127,7 @@ doScrollBy = do ->
shouldStopScrolling = (progress) ->
if activationId == time
- # This is the most recent animator and the key is still pressed, so keep going.
+ # This is the most recently-activated animator and we haven't yet seen its keyup event, so keep going.
false
else
duration <= progress
@@ -142,8 +143,6 @@ doScrollBy = do ->
# One final call of performScroll to check the visibility of the activated element.
performScroll(element, axisName, 0, true)
window.cancelAnimationFrame(animatorId)
- # Advance time if this is the most-recently activated animator and time hasn't otherwise advanced.
- time += 1 if activationId == time
else
animatorId = window.requestAnimationFrame(animate)